当前位置: 首页 > news >正文

C# 委托与匿名方法

文章目录

  • 1.委托的基本概念
    • 1.1 声明和使用委托
    • 1.2 委托的创建与调用
    • 1.3 委托的多播功能
  • 2. 委托的应用场景
    • 2.1 事件处理
    • 2.2 回调函数
    • 2.3 策略模式
  • 3.匿名方法
    • 3.1 定义匿名方法
    • 3.2 匿名方法的应用
  • 4.委托与匿名方法的实际应用示例
    • 4.1 使用委托实现回调函数
    • 4.2 使用匿名方法实现事件处理
    • 4.3 使用匿名方法作为回调
  • 5.委托与匿名方法的注意事项
    • 5.1 委托的类型安全
    • 5.2 委托的生命周期
    • 5.3 匿名方法的作用域

1.委托的基本概念

委托是一种引用类型,可以用来封装一个或多个方法,适合用于事件处理和回调的场景。委托的声明形式类似于方法签名,但它不是方法,而是方法的引用。

1.1 声明和使用委托

在 C# 中定义委托的语法如下:
    delegate 返回类型 委托名(参数列表);
例如,定义一个返回 int、接收两个 int 参数的委托:

delegate int MathOperation(int a, int b);

1.2 委托的创建与调用

    创建委托实例时,可以将一个符合签名的方法赋给它。以下是一个委托的基本使用示例:

using System;class Program
{// 定义委托delegate int MathOperation(int a, int b);// 定义符合委托签名的方法static int Add(int x, int y) => x + y;static int Multiply(int x, int y) => x * y;static void Main(){// 创建委托实例,并传入方法MathOperation addOperation = Add;MathOperation multiplyOperation = Multiply;// 调用委托Console.WriteLine(addOperation(3, 4));       // 输出: 7Console.WriteLine(multiplyOperation(3, 4));  // 输出: 12}
}

    MathOperation 委托可以引用任意符合 int (int, int) 签名的方法。

1.3 委托的多播功能

    委托还可以引用多个方法,这种特性被称为多播委托(Multicast Delegate)。可以通过 += 运算符将多个方法绑定到一个委托实例上,执行时会按顺序依次调用这些方法。

using System;class Program
{delegate void PrintMessage();static void Hello() => Console.WriteLine("Hello");static void World() => Console.WriteLine("World");static void Main(){PrintMessage message = Hello;message += World;message();  // 输出: Hello \n World}
}

在调用 message() 时,Hello 和 World 方法都会被依次调用。

2. 委托的应用场景

2.1 事件处理

    在 GUI 编程中,用户操作(如点击按钮)会触发事件。事件处理器通常使用委托进行实现,允许动态绑定处理方法。

2.2 回调函数

    在异步编程或长时间运行的任务中,回调函数非常有用。我们可以将回调函数定义为委托,以便任务完成后调用。

2.3 策略模式

    在设计模式中,策略模式允许我们在运行时动态选择算法。可以通过委托实现不同的算法,并在需要时进行切换。

3.匿名方法

    在 C# 2.0 及以上版本中,匿名方法 为委托提供了更加简洁的语法。匿名方法是一种不需要命名的方法,可以在创建委托实例时直接定义,减少代码量。

3.1 定义匿名方法

    匿名方法的语法是在 delegate 关键字后直接提供方法实现,而不需要方法名。

using System;class Program
{delegate void Greet(string name);static void Main(){Greet greet = delegate (string name){Console.WriteLine("Hello, " + name);};greet("Alice");  // 输出: Hello, Alice}
}

匿名方法 delegate (string name) { … } 实现了 Greet 委托所需的方法签名。

3.2 匿名方法的应用

  • 事件处理:为事件动态绑定方法。
  • 回调函数:实现简单的回调逻辑。
  • LINQ 查询:匿名方法在 LINQ 表达式中很常见。

4.委托与匿名方法的实际应用示例

4.1 使用委托实现回调函数

    假设我们有一个执行某种操作的长时间任务,任务完成后希望调用回调函数,可以使用委托实现。

using System;
using System.Threading;class Program
{// 定义回调委托delegate void TaskCompletedCallback(string message);static void Main(){// 传递回调方法作为参数PerformTask("Sample Task", TaskCompleted);}static void PerformTask(string taskName, TaskCompletedCallback callback){Console.WriteLine($"Starting {taskName}...");Thread.Sleep(2000);  // 模拟耗时操作// 任务完成后调用回调callback($"{taskName} completed successfully.");}static void TaskCompleted(string message){Console.WriteLine(message);}
}

在上述示例中,当 PerformTask 完成时会调用 TaskCompleted 方法,输出任务完成消息。

4.2 使用匿名方法实现事件处理

    在事件处理中,匿名方法可以使代码更加简洁。例如,创建一个按钮点击事件的处理器:

using System;
using System.Windows.Forms;class Program
{static void Main(){Button button = new Button();button.Text = "Click Me";// 使用匿名方法绑定事件处理器button.Click += delegate (object sender, EventArgs e){Console.WriteLine("Button clicked!");};Application.Run(new Form { Controls = { button } });}
}

在该例子中,button.Click 事件使用匿名方法直接定义了事件处理逻辑,无需创建单独的方法。

4.3 使用匿名方法作为回调

    在需要临时回调逻辑的场景下,匿名方法可以简化代码结构。以下是一个简单的计时器回调示例:

using System;
using System.Timers;class Program
{static void Main(){Timer timer = new Timer(1000);// 使用匿名方法定义回调timer.Elapsed += delegate (object sender, ElapsedEventArgs e){Console.WriteLine("Timer ticked at: " + e.SignalTime);};timer.Start();Console.ReadLine();timer.Stop();}
}

timer.Elapsed 事件使用匿名方法实现,简化了代码逻辑。

5.委托与匿名方法的注意事项

5.1 委托的类型安全

    委托类型必须与它引用的方法完全匹配,包括返回类型和参数列表,否则会导致编译错误。因此,定义委托时需要确保签名的一致性。

5.2 委托的生命周期

    在多播委托中,委托引用的多个方法顺序执行。如果在多播委托执行过程中发生异常,后续方法不会继续执行。因此,在实现多播委托时,需考虑异常处理的问题。

5.3 匿名方法的作用域

    匿名方法可以访问其声明作用域中的变量,允许捕获局部变量。这种特性在某些情况下会产生闭包(Closure)现象。需要注意,捕获的变量在委托生命周期内始终保持引用,因此可能导致预期外的行为。

using System;
using System.Collections.Generic;class Program
{static void Main(){List<Action> actions = new List<Action>();for (int i = 0; i < 3; i++){actions.Add(delegate { Console.WriteLine(i); });}foreach (var action in actions){action();  // 输出的值可能不符合预期,因为 i 是引用捕获}}
}

由于匿名方法捕获了 i 的引用,而不是值,因此最后输出的都是循环结束后的 i 值。


http://www.mrgr.cn/news/70868.html

相关文章:

  • docker save 和 docker load介绍
  • MySQL查询某个数据库中特定表的空间占用大小
  • vue3使用VueQuill插入自定义按钮
  • C++开发基础之使用librabbitmq库实现RabbitMQ消息队列通信
  • MySQL多系统安装配置教程(Windows、Ubuntu、Centos)
  • 前端 终端console.log() 不同颜色的输出工具chalk的介绍与使用 平替chalk的工具
  • 微知-tar命令如何只查看tgz文件内容不解压
  • 精品案例PPT | 企业架构及典型设计方案
  • 大数据应用开发——实时数据采集
  • Vue.js 组件开发详解
  • 斗破QT编程入门系列之四:GUI应用程序设计基础:UI文件设计原理与运行机制(五星斗师)
  • 腾讯云边缘安全加速平台EdgeOne最佳实践
  • 拾贝(Shibei):微信读书笔记管理的新篇章
  • 如何使用Flask编写一个网站
  • Ubuntu 20.04配置ollama并下载安装调用本地大语言模型
  • 探索jQuery与原生JavaScript:事件绑定的比较
  • 网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
  • 【Kettle实战】按日期变量批量执行任务[附全部job和tras配置图]
  • 河南测绘资质办理注意事项
  • AI 大模型如何重塑软件开发流程与模式
  • 深入理解Python字符串:常用查找方法、去除首位信息、大小写转换与排版
  • Elasticsearch(ES)简介
  • 群晖NAS上部署Photopea并实现随时随地高效图片处理
  • 2024下半年软考系统架构师案例分析题试题与答案--Cache-aside
  • debug
  • Nginx 部署负载均衡服务全解析