C# --- 委托(Delegates)和事件(Events)

5.1 委托(Delegates)

> 1 委托是C#中非常强大的特性,类似于C++中的函数指针,但更加类型安全和灵活。委托可以引用一个方法,或者一组方法,当调用委托时,它会执行引用的方法。委托特别适合用于实现回调机制和事件驱动编程。

> 2 想象一下,你是一位活动策划师,你需要组织一场大型活动。在活动中,有很多不同的任务需要完成,比如安排音乐、布置场地、准备食物等等。你可以自己去做所有的事情,但更好的方法是让专业人士来帮你完成这些任务。

委托在编程中就像是这些专业人士。你可以把一个任务委托给一个方法,当需要完成这个任务时,你只需要调用这个委托,而不需要知道具体是哪个方法在执行任务。委托是一种类型安全的函数指针,可以指向一个或多个方法,并在需要时调用它们。

5.1.1 委托的定义和使用

(1) 定义委托:public delegate void MyDelegate(string message);

(2) 声明和实例化委托:

> (1) MyDelegate del = new MyDelegate(MethodB);

> (2) MyDelegate del = MethodB;

以上两种实例方式的效果和意义是一样的,都是将 MethodB 分配给一个新的 MyDelegate 类型的委托实例。不同的是,第一种方式显式地使用了 new 关键字来创建委托实例,而第二种方式是语法糖,编译器会自动将其转换为第一种方式。

(3) 使用委托:del("Hello, World!");

5.1.2 示例

// 定义一个委托类型,名为 MyDelegate,接受一个字符串参数并返回 void
public delegate void MyDelegate(string message);
class Program
{
    static void Main()
{
    // 声明和实例化委托,并将 MethodA 分配给它
    MyDelegate del = MethodA;

    // 调用委托,实际调用 MethodA 方法
    del("Hello from MethodA");

    // 将委托指向 MethodB
    del = MethodB;

    // 调用委托,实际调用 MethodB 方法
    del("Hello from MethodB");
}



// 符合委托签名的方法 MethodA
static void MethodA(string message)
{
    Console.WriteLine(message);
}

// 符合委托签名的方法 MethodB
static void MethodB(string message)
{
    Console.WriteLine(message);
}

在这个示例中,MyDelegate是一个委托类型,它可以引用任何接受一个字符串参数并返回void的方法。MethodA和MethodB是两个符合该签名的方法,我们可以将它们分配给del委托并调用它们。

5.1.3 拓展

(1)自定义委托

// 定义一个自定义委托类型
public delegate int AddDelegate(int x, int y);

class Program
{
    static void Main()
    {
        // 使用自定义委托类型
        AddDelegate add = (x, y) => x + y;
        Console.WriteLine(add(2, 3)); // 输出 5
    }
}

> 相等于  ---》 (2) Func 委托

class Program
{
    static void Main()
    {
        // 使用 Func 委托
        Func<int, int, int> add = (x, y) => x + y;
        Console.WriteLine(add(2, 3)); // 输出 5
    }
}

> 详细解释

.    Func<int, int, int>:

..   第一个 int:表示方法的第一个参数的类型。

...  第二个 int:表示方法的第二个参数的类型。

.... 第三个 int:表示方法的返回值的类型。

5.1.4 多播委托

多播委托是 C# 中的一种特殊委托类型,它允许一个委托实例包含对多个方法的引用。当调用该委托时,它会依次调用所有被引用的方法。多播委托在事件处理和回调机制中非常有用。

(1) 特点

.   多个方法调用:多播委托可以包含对多个方法的引用,当调用该委托时,会按顺序调用所有方法。

..  顺序执行:多播委托中的方法按添加顺序执行。

... 返回值处理:如果委托有返回值,多播委托只返回最后一个方法的返回值。

(2) 创建多播委托

可以使用 += 操作符将多个方法附加到一个委托实例上,使用 -= 操作符从委托实例中移除方法。

(3) 定义和使用多播委托

using System;


// 定义一个委托类型,接受一个字符串参数并返回 void
public delegate void MyDelegate(string message);


class Program
{
    static void Main()
    {
        // 声明一个 MyDelegate 类型的委托实例,并将 MethodA 分配给它
        MyDelegate del = MethodA;

        // 使用 += 操作符将 MethodB 附加到委托实例 del 上
        del += MethodB;

        // 调用委托实例 del,将依次调用 MethodA 和 MethodB,传递参数 "Hello from Delegate"
        del("Hello from Delegate");   //MethodA和MethodB都输出

        // 使用 -= 操作符从委托实例 del 上移除 MethodA
        del -= MethodA;

        // 再次调用委托实例 del,这次只会调用 MethodB,传递参数 "Hello again"
        del("Hello again");  //只输出MethodB
    }

    // 定义符合委托签名的第一个方法 MethodA
    static void MethodA(string message)
    {
        Console.WriteLine("MethodA: " + message);
    }

    // 定义符合委托签名的第二个方法 MethodB
    static void MethodB(string message)
    {
        Console.WriteLine("MethodB: " + message);
    }
}

(4) 处理返回值的多播委托

using System;

using System.Collections.Generic;

// 定义一个返回整数的委托类型,接受一个整数参数
public delegate int MyDelegate(int value);

class Program
{
    static void Main()
    {
        // 声明一个 MyDelegate 类型的委托实例,并将 MethodA 和 MethodB 分配给它
        MyDelegate del = MethodA;
        del += MethodB;

        // 调用委托并获取所有返回值
        List<int> results = InvokeDelegate(del, 5);

        // 输出所有返回值
        Console.WriteLine("Results:");
        foreach (int result in results)
        {
            Console.WriteLine(result);
        }
    }

    // 定义符合委托签名的第一个方法 MethodA
    static int MethodA(int value)
    {
        return value + 1; // 将输入值加 1
    }

    // 定义符合委托签名的第二个方法 MethodB
    static int MethodB(int value)
    {
        return value + 2; // 将输入值加 2
    }

    // 定义一个方法来调用多播委托并收集所有返回值
    static List<int> InvokeDelegate(MyDelegate del, int value)
    {
        List<int> results = new List<int>();

        // 使用 GetInvocationList 获取委托的调用列表
        foreach (MyDelegate handler in del.GetInvocationList())
        {
            // 调用每个方法,并将返回值添加到 results 列表中
            int result = handler(value);
            results.Add(result);
        }

        return results;
    }
}

5.2 事件(Events)

事件是基于委托的一种特殊成员,主要用于在一个对象希望通知另一个对象某些事情发生时使用。事件是一种发布-订阅模式的实现,通常用于UI编程和处理用户交互。

5.2.1 定义和使用事件

(1) 定义事件:

public event MyDelegate MyEvent;

(2) 触发事件:

protected virtual void OnMyEvent(string message)

{

    if (MyEvent != null) MyEvent(message);

}

(3) 订阅事件:

obj.MyEvent += new MyDelegate(EventHandler);

5.1.2 示例

public delegate void MyDelegate(string message);

class Publisher
{
    public event MyDelegate MyEvent;

    public void RaiseEvent(string message)
    {
        if (MyEvent != null) MyEvent(message);
    }
}
class Subscriber
{
    public void EventHandler(string message)
    {
        Console.WriteLine("Event received: " + message);
    }
}
class Program
{
    static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        // 订阅事件
        publisher.MyEvent += subscriber.EventHandler;

        // 触发事件
        publisher.RaiseEvent("Hello, Event!");
    }
}

在这个示例中,Publisher类定义了一个事件MyEvent,当事件触发时会调用所有订阅的处理程序。Subscriber类有一个EventHandler方法,它将被注册为事件处理程序。Publisher对象触发事件时,Subscriber对象的处理程序被调用。

> 委托是对方法的引用,可以存储和调用方法。适用于实现回调机制。

> 事件是基于委托的,用于实现发布-订阅模式,适用于通知其他对象某些事情发生。

  • 24
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜回.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值