C#中的委托用于定义方法签名,包括方法名和参数类型。主要用于编码回调机制。
1、委托的作用
1、实现回调功能(回调简单来说就是函数作为参数传入其他函数,然后在适当的时候由其他函数调用)
委托可以定义一个方法签名类型,但不实现具体逻辑。它可以指向不同的方法,这就实现了回调的概念。例如事件处理使用委托定义了事件类型,但交由开发者实现具体逻辑。
2、连接事件和处理程序
委托定义了事件的类型签名,同时可以记录多个处理方法。这就连接了事件源和事件处理程序。
3、异步编程基础
委托算是一个重要的异步模型组成部分。Async/Await使用委托实现了任务和回调函数的关联。
4、支持多线程编程
通过委托可以将方法放入线程池执行或启动新线程调用,实现多线程编程。
5、解耦调用关系
委托允许在运行时动态改变方法目标。调用者与被调用方法解耦了,这在IoC/DEP中很重要。
6、传递行为
委托允许把方法作为参数进行传递。例如比赛可以把获胜逻辑委托给不同的方法。
7、支持异步流程
委托可以支持一种流程驱动的异步编程模型,定义了任务依赖和执行顺序。
总之,委托作为.NET平台的一种基础设施,它支撑了C#中事件处理、异步编程、多线程以及其他更高级设计模式的实现。
委托主要应用场景
2、委托特点
3、委托声明
// 定义了无参无返回值的委托
delegate void EventHandler();
// 定义带有int参数和返回string的委托
delegate string ConvertDelegate(int i);
4、使用委托
public void Test(){}
EventHandler handler = Test;
handler(); // 调用Test方法
5、具体例子
下面通过一个例子来具体展示委托在C#中的使用:
1、定义一个包含两个整数参数和返回整数结果的委托:
delegate int Calculator(int a, int b);
2、定义两个实现上述委托方法签名的方法:
int Add(int a, int b) => a + b;
int Mul(int a, int b) => a * b;
3、创建委托实例并指向具体方法:
Calculator calc = Add;
4、调用委托:
int result = calc(1, 2); // result will be 3
5、可以改变委托指向的方法:
calc = Mul;
int result = calc(2, 3); // result will be 6
6、也可以让一个委托指向多个方法
calc += Mul;
int result = calc(2, 3); // result will be 6
result = calc(1, 2); // result will be 2
7、删除方法处理程序:
calc -= Mul;
通过这个例子可以看到,委托定义了一个回调函数签名,但不实现具体逻辑,可以动态地指向不同的方法。这就实现了回调功能;委托是C#异步和事件处理的基础设施。
6、委托的发布\订阅者模式(观察者模式)
发布/订阅模式是一种软件设计模式,可以用于实现软件组件之间的松耦合通信。在这个模式中:
以下是使用委托实现发布-订阅模式的基本步骤:
1、定义委托:首先,需要定义一个委托来描述订阅者可以接收的事件或消息的签名。委托可以是系统提供的预定义委托类型,如 Action
或 Func
,也可以自定义委托类型。
public delegate void MyEventHandler(string message);
2、声明事件或消息发布者:在发布者类中声明一个事件或消息,用于发布事件或消息。
public class Publisher
{
public event MyEventHandler MyEvent;
public void PublishMessage(string message)
{
if (MyEvent != null)
{
MyEvent(message);
}
}
}
3、创建订阅者:创建一个订阅者类,并定义订阅者对象接收事件或消息后的行为。
public class Subscriber
{
public void HandleMessage(string message)
{
Console.WriteLine("Received message: " + message);
}
}
4、订阅事件或消息:在订阅者对象中,使用 +=
运算符将订阅者的方法与事件或消息关联起来。
Subscriber subscriber = new Subscriber();
Publisher publisher = new Publisher();
publisher.MyEvent += subscriber.HandleMessage;
5、发布事件或消息:发布者对象通过调用事件或消息的发布方法,触发事件或发送消息。
publisher.PublishMessage("Hello, subscribers!");
在上述示例中,我们首先定义了一个名为 MyEventHandler
的委托,用于描述订阅者可以接收的事件或消息的签名。然后,我们在 Publisher
类中声明了一个 MyEvent
事件,并在 PublishMessage
方法中触发该事件。
接下来,我们创建了一个订阅者对象 subscriber
和一个发布者对象 publisher
。通过使用 +=
运算符,我们将订阅者的 HandleMessage
方法与发布者的 MyEvent
事件关联起来。
最后,我们通过调用 publisher.PublishMessage
方法,发布了一个消息。由于订阅者已经与该事件关联,订阅者对象的 HandleMessage
方法将被调用,并输出接收到的消息。
使用委托实现的发布-订阅模式可以实现对象之间的松耦合通信,发布者和订阅者之间的关联通过委托的机制来建立。这种模式可以用于很多场景,例如事件驱动编程、GUI 应用程序中的用户交互响应等。
*事件event是一种特殊的委托,它只能+=,-=,不能直接用=。event在定义类中(发布者)是可以直接=的,但是在其他类中(订阅者)就只能+= -=了,也就是说发布者发布一个事件后,订阅者针对他只能进行自身的订阅和取消。
1、以下是使用事件的基本步骤:
1、定义事件委托:首先,需要定义一个事件委托,它描述了订阅者可以处理的事件的签名。
public delegate void MyEventHandler(object sender, EventArgs e);
2、声明事件:在发布者类中声明一个事件,使用事件委托作为事件类型。
public class Publisher
{
public event MyEventHandler MyEvent;
protected virtual void OnMyEvent(EventArgs e)
{
MyEventHandler handler = MyEvent;
if (handler != null)
{
handler(this, e);
}
}
public void PublishEvent()
{
OnMyEvent(EventArgs.Empty);
}
}
3、创建订阅者:创建一个订阅者类,并定义订阅者对象处理事件的方法。
public class Subscriber
{
public void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Event handled by subscriber");
}
}
4、订阅事件:在订阅者对象中,使用 +=
运算符将订阅者的方法与事件关联起来。
Subscriber subscriber = new Subscriber();
Publisher publisher = new Publisher();
publisher.MyEvent += subscriber.HandleEvent;
5、发布事件:发布者对象通过调用事件的发布方法,触发事件。
publisher.PublishEvent();
在上述示例中,我们首先定义了一个名为 MyEventHandler
的事件委托,它描述了订阅者可以处理的事件的签名。然后,在 Publisher
类中声明了一个名为 MyEvent
的事件,并提供了一个受保护的虚拟方法 OnMyEvent
,用于触发事件并调用订阅者的处理方法。
接下来,我们创建了一个订阅者对象 subscriber
和一个发布者对象 publisher
。通过使用 +=
运算符,我们将订阅者的 HandleEvent
方法与发布者的 MyEvent
事件关联起来。
最后,我们通过调用 publisher.PublishEvent
方法,发布了一个事件。由于订阅者已经与该事件关联,订阅者对象的 HandleEvent
方法将被调用,输出相应的处理消息。
使用事件的主要优点是它提供了一种标准化的方式来实现发布-订阅模式,简化了代码的编写,并且提供了更好的可读性和可维护性。此外,事件还支持多个订阅者,使得多个对象可以同时订阅同一个事件并相应地处理。
EventHandler
是一个预定义的委托类型,在 C# 中常用于处理事件。它是一个通用委托,用于处理不带自定义事件数据的事件。
2、事件的异常
在事件驱动的编程模型中,一个发布者可以触发一个事件,并允许多个订阅者注册事件处理方法来响应该事件。
以下是一个示例,展示了一个发布者对应多个订阅者的情况:
public class Publisher
{
public event EventHandler MyEvent;
protected virtual void OnMyEvent()
{
EventHandler handler = MyEvent;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public void PublishEvent()
{
OnMyEvent();
}
}
public class Subscriber1
{
public void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Event handled by Subscriber 1");
}
}
public class Subscriber2
{
public void HandleEvent(object sender, EventArgs e)
{
Console.WriteLine("Event handled by Subscriber 2");
}
}
public class Program
{
public static void Main()
{
Subscriber1 subscriber1 = new Subscriber1();
Subscriber2 subscriber2 = new Subscriber2();
Publisher publisher = new Publisher();
publisher.MyEvent += subscriber1.HandleEvent;
publisher.MyEvent += subscriber2.HandleEvent;
publisher.PublishEvent();
// 输出:
// Event handled by Subscriber 1
// Event handled by Subscriber 2
}
}
在上述示例中,我们创建了两个订阅者对象 subscriber1
和 subscriber2
,它们都具有相同的事件处理方法 HandleEvent
。
然后,我们创建了一个发布者对象 publisher
,并将两个订阅者的事件处理方法注册到发布者的事件 MyEvent
上,使用 +=
运算符进行订阅。
当调用 publisher.PublishEvent()
方法时,发布者会触发事件,并通知所有注册的订阅者的事件处理方法。在本例中,两个订阅者的事件处理方法都会被调用,并输出相应的消息。
这样,一个发布者可以同时与多个订阅者进行关联,每个订阅者都可以独立地对事件进行处理。这种 模式允许松耦合的通信和更灵活的系统设计。
如果想让订阅的方法都执行处理的话,必须保证订阅者在订阅内包括订阅内的方法不能抛出异常,否则将不能按订阅执行。
Func
和 Action
都是委托类型,用于定义方法的签名和委托实例的创建。它们在 C# 中常用于传递方法作为参数或将方法作为返回值。
主要区别如下:
Func
委托用于具有返回值的方法,而 Action
委托用于没有返回值的方法。
Func
委托的最后一个类型参数表示方法的返回值类型,前面的类型参数表示方法的参数类型。例如,Func
表示具有一个整数参数并返回一个字符串的方法。Action
委托只表示没有返回值的方法,它的类型参数表示方法的参数类型。例如,Action
表示具有一个整数参数且没有返回值的方法。Func
委托可以具有从 0 到 16 个参数的方法,而 Action
委托可以具有从 0 到 16 个参数的方法。
Func
表示具有一个整数和一个字符串参数,并返回一个布尔值的方法。Action
表示具有一个整数和一个字符串参数,并且没有返回值的方法。public class Program
{
public static void Main()
{
Func addFunc = (a, b) => a + b;
int result = addFunc(2, 3);
Console.WriteLine(result); // 输出:5
Action greetAction = name => Console.WriteLine("Hello, " + name);
greetAction("Alice"); // 输出:"Hello, Alice"
}
}
在上述示例中,我们定义了一个 Func
委托类型的变量 addFunc
,它表示具有两个整数参数和一个整数返回值的方法。我们使用 lambda 表达式来实现这个方法的逻辑,并将其赋值给 addFunc
。
然后,我们调用 addFunc(2, 3)
,得到结果 5,并将结果输出到控制台。
类似地,我们定义了一个 Action
委托类型的变量 greetAction
,它表示具有一个字符串参数和没有返回值的方法。我们使用 lambda 表达式来实现这个方法的逻辑,并将其赋值给 greetAction
。
最后,我们调用 greetAction("Alice")
,它输出 “Hello, Alice” 到控制台。
通过使用 Func
和 Action
委托,我们可以更灵活地传递方法,使代码更为简洁和可读。Func
和 Action
在很多情况下都可以用作回调参数、LINQ 查询、异步编程等方面的工具。
委托和事件是 C# 中常用的两种机制,用于实现事件驱动的编程模型。它们有一些区别和不同的用途。
委托(Delegate)是一种类型,用于表示对一个或多个具有相同签名的方法的引用。它提供了一种将方法作为参数传递、存储方法引用和调用方法的方式。委托可以用于回调机制、事件处理和异步编程等场景。
事件(Event)是委托的一种特殊用法,它提供了一种机制,用于在类或对象发生特定动作或状态改变时通知其他类或对象。事件通过委托来实现,它定义了事件的签名,允许其他类注册和取消注册事件处理方法。事件的发布者(即包含事件的对象)负责触发事件,而订阅者(即注册了事件处理方法的对象)负责响应事件。
以下是委托和事件的一些对比:
delegate
关键字定义,而事件是在类中声明委托类型的事件。public delegate void MyDelegate(string message);
public class Publisher
{
public event MyDelegate MyEvent;
public void PublishMessage(string message)
{
Console.WriteLine("Publishing message: " + message);
OnMyEvent(message);
}
protected virtual void OnMyEvent(string message)
{
MyDelegate handler = MyEvent;
handler?.Invoke(message);
}
}
public class Subscriber
{
public void HandleMessage(string message)
{
Console.WriteLine("Received message: " + message);
}
}
public class Program
{
public static void Main()
{
Publisher publisher = new Publisher();
Subscriber subscriber1 = new Subscriber();
Subscriber subscriber2 = new Subscriber();
publisher.MyEvent += subscriber1.HandleMessage;
publisher.MyEvent += subscriber2.HandleMessage;
publisher.PublishMessage("Hello, world!");
// 输出:
// Publishing message: Hello, world!
// Received message: Hello, world!
// Received message: Hello, world!
}
}
在上述示例中,我们定义了一个委托类型 MyDelegate
,它表示具有一个字符串参数和没有返回值的方法。
然后,我们创建了一个发布者对象 publisher
和两个订阅者对象 subscriber1
和 subscriber2
。
通过 publisher.MyEvent += subscriber1.HandleMessage
和 publisher.MyEvent += subscriber2.HandleMessage
,我们将两个订阅者的方法注册为事件处理方法,订阅了 publisher
的 MyEvent
事件。
当调用 publisher.PublishMessage("Hello, world!")
发布消息时,事件被触发,订阅者的事件处理方法被调用,并输出相应的消息。
这个示例展示了委托和事件的使用,其中委托用于定义方法的签名和委托实例的创建,事件用于通知其他对象发生的特定动作。
总结起来,委托是一种通用的方法引用机制,而事件是一种特殊用途的机制,用于实现发布-订阅模型的事件通知。委托可以用于更广泛的场景,而事件则是委托在特定情况下的应用。