C# - 委托与事件

委托与事件

委托

委托的定义

委托是C#中的一种类型,用于存储对方法的引用。它允许将方法作为参数传递给其他方法,实现回调、事件处理和动态调用等功能。通俗来讲,就是委托包含方法的内存地址,方法匹配与委托相同的签名,因此通过使用正确的参数类型来调用方法。

委托的特性

  1. 引用方法:委托允许存储对方法的引用,使得方法可以被动态地调用。
  2. 类型安全:委托是类型安全的,它们在编译时会检查方法签名,确保委托实例只能引用与其声明的相同签名的方法。
  3. 多播性:委托支持多播,即一个委托实例可以引用多个方法。通过 += 和 -= 操作符,可以动态地添加或移除委托链中的方法。
  4. 异步编程:委托在异步编程中扮演了重要的角色,尤其是在使用 BeginInvoke 和 EndInvoke 进行异步操作时。
  5. 匿名方法和 Lambda 表达式:C# 支持使用匿名方法和 Lambda 表达式来创建简洁的委托实例,减少了样板代码的编写。
  6. 委托泛型化:C# 提供了泛型委托 Action 和 Func,分别用于表示没有返回值和有返回值的委托,减少了需要定义新委托类型的情况。

查看代码

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher("篮球先锋报");

        Observer observerA = new Observer("老A");
        publisher.Magazine += observerA.RecvMagazine;

        Observer observerB = new Observer("老B");
        publisher.Magazine += observerB.RecvMagazine;

        publisher.PublishMagezine();
        //或者使用下面的方式  区别就是一个在定义的内部触发,一个在外部触发
        publisher.Magazine?.Invoke(publisher.magazineName);
        Console.ReadKey();
    }
}

public class Observer
{
    private string name;
    public Observer(string name)
    {
        this.name = name;
    }

    public void RecvMagazine(string message)
    {
        Console.WriteLine($"{this.name} recv {message}, 仔细读了一番");
    }
}

public class Publisher
{
    public string magazineName;
    public Publisher(string magazineName)
    {
        this.magazineName = magazineName;
    }

    public delegate void MagazineDelegate(string message);
    public MagazineDelegate Magazine;

    public void PublishMagezine()
    {
        Magazine?.Invoke(this.magazineName);
    }
}

事件

查看代码

public class EventPublisher
{
    // 1. 定义委托类型
    public delegate void MyEventHandler(object sender, EventArgs e);
​
    // 2. 声明事件,使用 event 关键字
    public event MyEventHandler MyEvent;
​
    // 3. 编写引发事件的方法
    protected virtual void OnMyEvent()
    {
        // 4. 引发事件,安全调用委托
        MyEvent?.Invoke(this, EventArgs.Empty);
    }
}

查看代码

class Program
{
    static void Main(string[] args)
    {
        Publisher publisher = new Publisher("篮球先锋报");

        Observer observerA = new Observer("老A");
        publisher.Magazine += observerA.RecvMagazine;

        Observer observerB = new Observer("老B");
        publisher.Magazine += observerB.RecvMagazine;

        publisher.PublishMagezine();
        //下面的方式会出现编译错误  只允许在定义的内部触发,不允许在外部触发
        publisher.Magazine?.Invoke(publisher.magazineName);
        Console.ReadKey();
    }
}

public class Observer
{
    private string name;
    public Observer(string name)
    {
        this.name = name;
    }

    public void RecvMagazine(string message)
    {
        Console.WriteLine($"{this.name} recv {message}, 仔细读了一番");
    }
}

public class Publisher
{
    public string magazineName;
    public Publisher(string magazineName)
    {
        this.magazineName = magazineName;
    }

    public delegate void MagazineDelegate(string message);
    public event MagazineDelegate Magazine;

    public void PublishMagezine()
    {
        Magazine?.Invoke(this.magazineName);
    }
}

经典面试题

猫叫、老鼠跑了,主人醒来了

查看代码

class Program
{
    static void Main(string[] args)
    {
        Cat cat = new Cat();
        Mouse m = new Mouse(cat);
        People p = new People(cat);
        cat.Scream();
    }
}

public class Cat
{
    public delegate void ScreamHandler();
    public event ScreamHandler OnScream;

    public void Scream()
    {
        Console.WriteLine("猫叫了一声");
        OnScream?.Invoke();
    }

}

public class Mouse
{
    public Mouse(Cat c)
    {
        c.OnScream += () => { Console.WriteLine("老鼠跑了"); };
    }
}

public class People
{
    public People(Cat c)
    {
        c.OnScream += () => { Console.WriteLine("主人醒来了"); };
    }
}

//输出:
//猫叫了一声
//老鼠跑了
//主人醒来了

委托与事件的区别

  1. 事件基于委托,但并非委托 可以把事件看成委托的代理。在使用者看来,只有事件,而没有委托。
  2. 事件是对委托的包装 保护委托字段,对外不开放。所以外部对象没法直接操作委托。提供了 Add 和 Remove 方法,供外部对象订阅事件和取消事件。事件的处理方法在对象外部定义,而事件的执行是在对象的内部。至于事件的触发,何时何地无所谓。

什么时候使用委托与事件?

如果一个委托不需要再其定义的类之外被触发,那么就可以将其转化为事件,这样可以保证它不会在外部被随意触发。

相关推荐

  1. C#委托事件

    2024-06-10 16:38:05       38 阅读
  2. C# 委托事件

    2024-06-10 16:38:05       43 阅读
  3. C# - 委托事件

    2024-06-10 16:38:05       27 阅读
  4. C# 委托事件 深入

    2024-06-10 16:38:05       30 阅读
  5. 详解C#委托事件

    2024-06-10 16:38:05       31 阅读
  6. 二、C#基础语法( 委托事件

    2024-06-10 16:38:05       55 阅读
  7. C# 系统学习(事件委托

    2024-06-10 16:38:05       37 阅读
  8. C# 委托事件 终章

    2024-06-10 16:38:05       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-10 16:38:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-10 16:38:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-10 16:38:05       82 阅读
  4. Python语言-面向对象

    2024-06-10 16:38:05       91 阅读

热门阅读

  1. 如何进行《我的世界》基于Spigot的插件开发

    2024-06-10 16:38:05       29 阅读
  2. 前端构建工具总结

    2024-06-10 16:38:05       26 阅读
  3. docker部署mysql+nginx+redis

    2024-06-10 16:38:05       29 阅读
  4. 大数据领域的workload是什么意思?

    2024-06-10 16:38:05       25 阅读
  5. “抖动“ 与工作集

    2024-06-10 16:38:05       23 阅读
  6. GPT大模型微调-提高垂直领域回答质量

    2024-06-10 16:38:05       33 阅读
  7. 关于我做了一个python项目的总结

    2024-06-10 16:38:05       26 阅读
  8. Python 编程时可能会遇到各种错误提示

    2024-06-10 16:38:05       28 阅读
  9. Python 中生成器与普通函数的区别

    2024-06-10 16:38:05       30 阅读
  10. 2024.6.10 刷题总结

    2024-06-10 16:38:05       27 阅读
  11. 线程安全应用:

    2024-06-10 16:38:05       24 阅读
  12. 01-今日课程介绍

    2024-06-10 16:38:05       33 阅读