委托是一个类,它定义了方法的类型,使得可以将方法当做另一个方法的参数来进行传递。这种将方法动态的赋给参数的做法,可以避免在一个程序中大量使用if…else…(switch)语句,同时使得程序有更好的扩展性。
委托是一种引用类型,所以它具有引用类型所具有的通性。它保存的不是实际值,而是保存对存储在托管堆中对象的引用。那它保存的是对什么的引用呢?委托保存的是对函数的引用。
简单来说委托就是封装了方法的变量。
任何委托都继承自System.MulticastDelegate。
.NET中的委托是类型安全的,委托会检测它所保存的函数引用是否和声明的委托匹配。
1.相当于用方法作为另一方法参数(类似于C的函数指针)
2.在两个不能直接调用的方法中作为桥梁,如:在多线程中的跨线程的方法调用就得用委托
3.当不知道方法具体实现什么时使用委托,如:事件中使用委托
public delegate int Calculation(int x, int y);
public delegate int Calculation(int x, int y);
//为委托创建一个加法计算方法
public static int AddMethod(int x, int y)
{
int result = x + y;
return result;
}
//为委托创建一个乘法计算方法
public static int MulMethod(int x, int y)
{
int result = x * y;
return result;
}
static void Main(string[] args)
{
//将加法计算方法赋值给委托
Calculation cal = AddMethod;
//调用委托
int add = cal(1, 2);
//将乘法计算方法绑定同一个委托
cal += MulMethod;
//调用委托
int mul = cal(1, 2);
//将乘法计算方法删除
cal -= MulMethod;
//调用委托
int result = cal(1, 2);
Console.WriteLine($"计算结果:{add}");
Console.WriteLine($"计算结果:{mul}");
Console.WriteLine($"计算结果:{result }");
Console.ReadKey();
}
输出结果:
计算结果:3
计算结果:2
计算结果:3
以上示例可以看出委托的一个特性:可以将方法赋值给同一个委托,或者将多个方法绑定到同一个委托,当调用这个委托时候,将依次调用其所绑定的方法。
注意:第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”。将出现“使用了未赋值的局部变量”的编译错误。
同理如果要删除调用列表中的方法,请使用 “-” 或 “-=” 运算符。
尽管并非必需,但是我们发现很多的委托定义返回值都为 void,为什么呢?这是因为委托变量可以供多个订阅者注册,如果定义了返回值,那么多个订阅者的方法都会向发布者返回数值,结果就是后面一个返回的方法值将前面的返回值覆盖掉了,因此,实际上只能获得最后一个方法调用的返回值。可以运行上面的代码测试一下。除此以外,发布者和订阅者是松耦合的,发布者根本不关心谁订阅了它的事件、为什么要订阅,更别说订阅者的返回值了,所以返回订阅者的方法返回值大多数情况下根本没有必要。
有返回值的委托类型的泛型委托类型:
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
...
使用例子:
static void Main(string[] args)
{
//实例化Func委托
Func<int> func = new Func<int>(GetNumValue);
Func<int> func = GetNumValue;
//将lambda表达式分配给Func委托
Func<int> func = () => GetNumValue();
//将匿名方法分配给Func委托
Func<int> func = delegate () { return GetNumValue(); };
Console.WriteLine($"计算结果:{func()}");
Console.ReadKey();
}
static int GetNumValue()
{
return 1;
}
public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
...
public delegate bool Predicate<in T>(T obj);