源码链接: 码云
1 什么是委托
这个名词困惑了了我好久,应该对比C++中的函数指针(一个指向函数的指针),理解了函数指针就理解委托了.
函数指针的就是一个指针变量指向函数,例子如下,定义了一个*pf的函数指针,入参是两个int,返回值也是int,将pf的地址指向max函数,这样pf也能使用max函数.
//函数实例
//定义函数
int max(int a,int b){
return a>b?a;b;
}
//定义函数指针
int (*pf)(int, int);
//指针指向函数
pf = max;
//使用函数指针
int result = pf(1,5);
2 函数指针与委托的区别
C# 中的委托与 C++ 中的函数指针在概念上有相似之处,都是用来引用函数或方法的。然而,它们在实际使用和安全性上有很大的不同。C# 的委托是完全面向对象的,提供了更高的安全性和易用性。
以下是 C# 委托与 C++ 函数指针之间的一些主要区别:
安全性
-
类型安全:C# 的委托是类型安全的,意味着它们只能引用具有特定签名(返回类型和参数列表)的方法。尝试将不匹配的方法赋值给委托会导致编译错误。而 C++ 的函数指针在类型安全方面较为宽松,可能导致运行时错误。
-
内存管理:在 C# 中,委托由垃圾回收器(Garbage Collector)自动管理,这减少了内存泄漏的风险。而在 C++ 中,使用函数指针时需要手动管理内存,如果不当处理可能导致内存泄漏或其他问题。
面向对象特性
-
封装对象实例和方法:C# 的委托可以封装对象实例和方法,这意味着它们可以引用实例方法或静态方法。当委托被调用时,它会自动处理对象实例的绑定和方法的调用。相比之下,C++ 的函数指针只引用函数,不涉及对象实例。
-
多播和事件:C# 的委托支持多播(即一个委托可以引用多个方法),并且可以与事件一起使用,提供了一种发布-订阅机制。而 C++ 的函数指针通常只引用单个函数,不支持多播或事件机制。
便捷性
-
Lambda 表达式和匿名方法:C# 允许使用 Lambda 表达式和匿名方法来创建委托实例,这使得编写简短且灵活的代码变得容易。而 C++ 则没有类似的特性。
-
委托链和返回值处理:在 C# 中,当委托引用多个方法时,可以定义这些方法的调用顺序(链式调用),并且可以处理返回值(例如,通过最后一个调用的方法返回结果)。而在 C++ 中,函数指针通常只引用单个函数,返回值处理需要手动进行。
总结: 虽然 C# 的委托和 C++ 的函数指针在概念上相似,但它们在安全性、面向对象特性和便捷性方面存在显著差异。C# 的委托提供了更高级别的抽象和安全性,使得在 C# 中使用函数引用变得更加简单、安全和灵活。
3 如何使用委托
1 声明委托
委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。
//委托可以在类外声明,该委托的引用方法入参是string,返回值是void
public delegate void Callback(string message);
public class MyDelegateClass
{
//委托也可以在类内声明,该委托的引用方法入参是两个int,返回值也是int
public delegate int InternalDelegate(int a,int b);
}
2 实例化委托
Callback callback = MethodClass.WriteMessage;//实例化委托,并绑定方法
3 使用委托
callback("sunny老师,你好");
4 使用Lambda表达式创建委托的实例
{
//有入参无出参,委托实例用lambda表达式实例化
Callback callback = (s) =>
{
Console.WriteLine($"传递进来的参数是{s}");
};
callback("keson");
}
{
//有入参有出参,委托实例用lambda表达式实例化
MyDelegateClass myDelegateClass = new MyDelegateClass();
MyDelegateClass.MaxValueDelegate HandlerMaxValue = (a, b) =>
{
return a > b ? a : b;
};
int result = HandlerMaxValue(5, 13);
Console.WriteLine(result);
}
5 多播委托
多播委托(Multicast Delegate)是委托的一个特性,它允许将多个方法关联到同一个委托实例上,并可以在一次调用中执行所有关联的方法。多播委托是通过使用 +=
运算符将方法添加到委托实例中,或使用 -=
运算符从委托实例中移除方法来实现的。当委托被调用时,所有添加到该委托的方法都会按照它们被添加的顺序依次执行。
Callback callback = MethodClass.WriteMessage;//添加第一个方法
callback += MethodClass.PrintMessage;//添加第二个方法
callback("sunny老师,你好");
6 回调函数
将委托作为参数传递,同时在其他方法中使用该委托.
{
//回调函数:将委托作为参数进行传递
Callback callback = MethodClass.WriteMessage;//实例化委托
MethodClass.MethodWithCallback(4, 7, callback);//将委托作为参数传递
}
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());//在方法中使用委托
}
7 完整代码
- 方法类
public class MethodClass
{
public static void WriteMessage(string message)
{
Console.WriteLine($"方法一的信息是:{message}");
}
public static void PrintMessage(string message)
{
Console.WriteLine($"方法二的信息是:{message}");
}
public static int MaxValue(int a, int b)
{
return a > b ? a : b;
}
public static void MethodWithCallback(int param1, int param2, Callback callback)
{
callback("The number is: " + (param1 + param2).ToString());
}
}
- 委托类
//委托类
//委托可以在类外声明,该委托的引用方法入参是string,返回值是void
public delegate void Callback(string message);
public class MyDelegateClass
{
//委托也可以在类内声明,该委托的引用方法入参是两个int,返回值也是int
public delegate int MaxValueDelegate(int a,int b);
}
- 主函数
//主函数
{
//如何使用类内委托
//实例化委托类
MyDelegateClass myDelegateClass = new MyDelegateClass();
// 实例化委托
MyDelegateClass.MaxValueDelegate HandlerMaxValue = MethodClass.MaxValue;
//使用委托调用方法
int result = HandlerMaxValue(1, 56);
Console.WriteLine(result);
}
{
//如何使用类外的委托
Callback callback = MethodClass.WriteMessage;
callback("sunny老师,你好");
}
{
//实例化委托的另外一写法
Callback callback = new Callback(MethodClass.WriteMessage);
callback("sunny老师回复,同学们好呀"!);
}
{
//回调函数:将委托作为参数进行传递
Callback callback = MethodClass.WriteMessage;
MethodClass.MethodWithCallback(4, 7, callback);
}
{
//有入参无出参,委托实例用lambda表达式实例化
Callback callback = (s) =>
{
Console.WriteLine($"传递进来的参数是{s}");
};
callback("keson");
}
{
//有入参有出参,委托实例用lambda表达式实例化
MyDelegateClass myDelegateClass = new MyDelegateClass();
MyDelegateClass.MaxValueDelegate HandlerMaxValue = (a, b) =>
{
return a > b ? a : b;
};
int result = HandlerMaxValue(5, 13);
Console.WriteLine(result);
}
{
//委托的多播
Callback callback = MethodClass.WriteMessage;//添加第一个方法
callback += MethodClass.PrintMessage;//添加第二个方法
callback("sunny老师,你好");
}