C#中的委托和事件

委托 

 委托(Delegate)是C#中一种特殊的类型,它用于封装方法的引用。委托可以看作是类型安全的函数指针,允许你将方法作为参数传递给其他方法、从方法返回方法或者存储在变量中以备后用。委托在事件处理、回调函数和异步编程等场景中非常有用。

委托的基本概念

  1. 定义委托:首先需要定义一个委托类型,指定它可以引用的方法签名(包括返回类型和参数列表)。
  2. 实例化委托:然后创建该委托类型的实例,并将其与具体的方法关联起来。
  3. 调用委托:最后,可以通过委托实例来调用与之关联的方法。

定义和使用委托

1. 定义委托类型

public delegate void MyDelegate(string message);

这行代码定义了一个名为 MyDelegate 的委托类型,它可以引用任何具有 void 返回类型并接受一个 string 参数的方法。

2. 创建委托实例并关联方法

class Program
{
    // 定义一个符合委托签名的方法
    public static void PrintMessage(string message)
    {
        Console.WriteLine($"消息: {message}");
    }

    static void Main(string[] args)
    {
        // 创建委托实例,并将其与 PrintMessage 方法关联
        MyDelegate del = new MyDelegate(PrintMessage);

        // 或者更简洁地使用 lambda 表达式
        MyDelegate delLambda = (msg) => Console.WriteLine($"消息: {msg}");

        // 调用委托
        del("Hello, World!");
        delLambda("Hello from Lambda!");
    }
}

输出:

消息: Hello, World!
消息: Hello from Lambda!

1. 回调机制

委托允许你将一个方法作为参数传递给另一个方法,从而实现在特定条件下或操作完成后调用该方法的能力。这种模式称为回调。

示例:文件处理完成后的回调
using System;

public delegate void FileProcessCallback(string message);

class Program
{
    static void Main()
    {
        string filePath = "example.txt";
        ProcessFile(filePath, OnFileProcessed);
    }

    static void ProcessFile(string path, FileProcessCallback callback)
    {
        // 模拟文件处理逻辑
        Console.WriteLine($"正在处理文件: {path}");
        
        // 文件处理完成后调用回调
        callback("文件处理已完成!");
    }

    static void OnFileProcessed(string message)
    {
        Console.WriteLine(message);
    }
}

 callback("文件处理已完成!"); 是调用委托实例 callback 的方式。这行代码的作用是触发与 callback 关联的方法,并将字符串 "文件处理已完成!" 作为参数传递给该方法。

2. 事件处理

委托是实现事件驱动编程模型的基础。通过定义事件和订阅事件处理程序,对象可以在某些状态变化时通知其他对象,而无需直接依赖这些对象。

示例:按钮点击事件
using System;

public class Button
{
    // 定义一个事件
    public event EventHandler Click;

    public void OnClick()
    {
        Console.WriteLine("按钮被点击了");
        Click?.Invoke(this, EventArgs.Empty);
    }
}

class Program
{
    static void Main()
    {
        var button = new Button();
        
        // 订阅事件
        button.Click += Button_Click;

        // 模拟点击按钮
        button.OnClick();
    }

    private static void Button_Click(object sender, EventArgs e)
    {
        Console.WriteLine("处理按钮点击事件");
    }
}
  • Click:这里假设Click是一个事件(Event)。在C#中,事件通常用来通知其他对象某些事情发生了。
  • ?.:这是空条件运算符(Null-conditional operator),它是在C# 6.0中引入的。这个运算符允许你安全地调用方法或访问属性、事件等成员,即使对象是null也不会抛出异常。如果左侧的操作数是null,则操作停止并且整个表达式的值为null。
  • Invoke:这是委托(Delegate)的一个方法,用来立即执行订阅了该事件的所有方法。换句话说,它触发了事件,所有订阅了Click事件的监听者都会被通知到,并且会执行相应的事件处理代码。
  • (this, EventArgs.Empty):这里是传递给事件处理程序的参数。this通常指的是当前实例,即触发事件的对象。EventArgs.Empty表示没有特定的事件数据要传递,或者说是使用了一个空的事件参数。
  • 这行代码的意思是:如果有任何订阅者监听了Click事件,并且Click不是null,那么就调用Invoke方法来触发这个事件,同时传递当前对象和一个空的事件参数给所有的事件处理程序。

3. 多播委托(Multicast Delegates)

委托可以链接多个方法,形成一个多播委托。当调用这个委托时,所有链接的方法都会被依次执行。这在需要同时触发多个动作的情况下非常有用。

示例:多播委托
using System;

public delegate void MyDelegate(string message);

class Program
{
    public static void Method1(string message)
    {
        Console.WriteLine($"Method1: {message}");
    }

    public static void Method2(string message)
    {
        Console.WriteLine($"Method2: {message}");
    }

    static void Main()
    {
        MyDelegate del = Method1;
        del += Method2;

        del("Calling multiple methods via delegate.");
    }
}

事件

 1. 事件的基本概念

a. 委托(Delegate)

事件是基于委托的。委托是一种类型安全的函数指针,它可以引用一个或多个方法。定义事件的第一步是声明一个委托。

public delegate void MyEventHandler(object sender, EventArgs e);
b. 事件(Event)

事件是对委托的封装,它提供了对事件处理程序的添加和移除功能。事件只能在其声明的类内部触发。

public event MyEventHandler MyEvent;

2. 事件的使用步骤

a. 定义委托

首先定义一个委托,该委托将作为事件处理程序的签名。

public delegate void NotifyEventHandler(object sender, EventArgs e);
b. 声明事件

在类中声明一个事件,通常使用上述定义的委托类型。

public class Publisher
{
    // 声明事件
    public event NotifyEventHandler NotifyEvent;

    // 触发事件的方法
    protected virtual void OnNotify(EventArgs e)
    {
        NotifyEvent?.Invoke(this, e); // 使用空合并运算符确保线程安全
    }
}
c. 订阅事件

其他类可以通过注册事件处理程序来订阅事件。

public class Subscriber
{
    private Publisher _publisher;

    public Subscriber(Publisher publisher)
    {
        _publisher = publisher;
        // 订阅事件
        _publisher.NotifyEvent += HandleNotify;
    }

    private void HandleNotify(object sender, EventArgs e)
    {
        Console.WriteLine("事件已触发!");
    }
}
d. 触发事件

当特定条件满足时,发布者类可以触发事件,通知所有订阅者。

public class Publisher
{
    // ... 其他代码

    public void DoSomething()
    {
        // 模拟一些操作
        Console.WriteLine("执行了一些操作...");
        
        // 触发事件
        OnNotify(EventArgs.Empty);
    }
}

 示例1

using System;

// 定义一个简单的事件处理程序,不携带额外数据
public class Button
{
    // 声明一个事件,这里我们使用内置的EventHandler委托
    public event EventHandler Clicked;

    // 模拟按钮被点击的方法
    public void SimulateClick()
    {
        Console.WriteLine("按钮被点击了...");
        // 触发事件
        OnClick();
    }

    // 触发Clicked事件的方法
    protected virtual void OnClick()
    {
        // 使用?.操作符确保在没有订阅者时不会抛出异常
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

// 订阅者类,例如窗体或控制台应用程序的一部分
public class Form
{
    private readonly Button _button;

    // 构造函数中订阅按钮的点击事件
    public Form(Button button)
    {
        _button = button;
        _button.Clicked += HandleButtonClick; // 订阅事件
    }

    // 事件处理方法
    private void HandleButtonClick(object sender, EventArgs e)
    {
        Console.WriteLine("响应按钮点击:显示消息框!");
    }
}

// 程序入口
class Program
{
    static void Main(string[] args)
    {
        // 创建按钮实例
        var button = new Button();

        // 创建窗体实例,并传入按钮实例(订阅按钮的点击事件)
        var form = new Form(button);

        // 模拟按钮点击
        button.SimulateClick();

        Console.ReadLine(); // 阻塞主线程以便查看输出结果
    }
}

  示例2

using System;

// 1. 定义一个自定义委托,它将作为事件的基础
public delegate void NotificationHandler(string message);

// 2. 发布者类 - Notifier
public class Notifier
{
    // 3. 声明一个基于自定义委托的事件
    public event NotificationHandler Notify;

    // 4. 触发事件的方法
    public void TriggerNotification(string message)
    {
        Console.WriteLine($"正在触发通知: {message}");
        // 使用?.操作符确保在没有订阅者时不会抛出异常
        Notify?.Invoke(message);
    }
}

// 5. 订阅者类 - Listener
public class Listener
{
    private readonly Notifier _notifier;

    // 构造函数中订阅通知事件
    public Listener(Notifier notifier)
    {
        _notifier = notifier;
        _notifier.Notify += HandleNotification; // 订阅事件
    }

    // 6. 事件处理方法
    private void HandleNotification(string message)
    {
        Console.WriteLine($"收到通知: {message}");
    }

    // 不再需要监听时移除事件处理程序(防止内存泄漏)
    public void Unsubscribe()
    {
        _notifier.Notify -= HandleNotification;
    }
}

// 程序入口
class Program
{
    static void Main(string[] args)
    {
        // 创建通知者实例
        var notifier = new Notifier();

        // 创建监听者实例,并传入通知者实例(订阅通知事件)
        var listener = new Listener(notifier);

        // 模拟触发通知
        notifier.TriggerNotification("欢迎来到我们的平台!");

        // 如果不再需要监听者,记得取消订阅
        // listener.Unsubscribe();

        Console.ReadLine(); // 阻塞主线程以便查看输出结果
    }
}

你可能感兴趣的:(java,前端,javascript)