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

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));       // 输出: 7
        Console.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.kler.cn/a/389967.html

相关文章:

  • 鸿蒙next版开发:ArkTS组件点击事件详解
  • 深入理解BERT模型配置:BertConfig类详解
  • 十三、注解配置SpringMVC
  • 一文详解java的数据类型
  • 【CSS】“flex: 1“有什么用?
  • MTSET可溶于DMSO、DMF、THF等有机溶剂,并在水中有轻微的溶解性,91774-25-3
  • css中的变量使用
  • kafka分区中的ISR、OSR、AR 是什么?
  • Flink使用SQL Gateway提交SQL Job到远程集群
  • 【单例模式】饿汉式与懒汉式以及线程安全
  • 大数据技术在金融风控中的应用
  • 我的生活记(dz-cn)
  • 【CentOS】中的Firewalld:全面介绍与实战应用(下)
  • 论文阅读分享:基于弱监督的病理图像腺体分割
  • 现代Web开发:WebSocket 实时通信详解
  • C语言命令行参数解析:getopt函数实战指南及高级应用解析
  • mysql5常用命令(一)
  • centos7 arm版本编译qt5.6.3详细说明
  • 图形几何之美系列:仿射变换矩阵之先转后偏
  • QtLua
  • 容器技术在DevOps中的应用
  • 【unity】unity2021 URP管线下 SceneView没有MipMaps选项了怎么办?扩展Rendering Debugger工具
  • 单位正交矢量的参数化,用于特征矢量对厄尔米特矩阵对角化使用
  • PyQt5实战——翻译的实现,成功爬取微软翻译(可长期使用)经验总结(九)
  • R 语言数据分析常用操作指令
  • vue中调用全屏方法、 elementUI弹框在全屏模式下不出现问题、多级嵌套弹框蒙层遮挡问题等处理与实现方案