委托的简要讲解,适合初学者,如有说的不对、不合适地方,请帮我指出。
一、委托是什么
委托是持有一个或多个方法的对象
如果你有一个委托,并把一个或多个方法绑在这个委托上
当你调用委托时,就会调用此委托绑定的方法
二、为什么需要委托
①使用委托可以将方法像参数一样传入
方法的传参不能是另一个方法,但可以是一个委托,故一般将方法绑在委托上再用于传参,
可以增加代码的灵活性和复用性。
②实现方法的跨层级调用
举个例子,现在有DAL,BLL,UI三层架构(其中BLL引用DAL,UI引用BLL和DAL),如果
想在底层DAL调用上层(BLL,UI)的方法该怎么做呢,常规的直接调用肯定是不行的,因为
上层的对象对底层是不可见的,更别谈调用。
这个时候可以在DAL里写一个委托,再到上层将DAL里的委托绑定目标方法,此时我们在DAL
里面想调用上层方法时直接使用这个委托来调就可以了。
三、如何定义和使用委托
①委托的定义
知道了委托的定义和用处,现在我们可以来定义和使用委托了
委托的定义如上图,关键字delegate,声明名称、返回值和传参类型即可
此处我们定义了一个传参个数1、类型为int、无返回值的委托MyDelegate
②委托的使用
上面我们定义了委托MyDelegate
然后在需要的地方创建该委托类型的变量,用传参、返回值相同的方法和这个委托绑定即可
示例如下:
class MyClass
{
void Printf1(int x)
{
Console.WriteLine(x);
}
void Printf2(int x)
{
Console.WriteLine(x + 1);
}
public MyDelegate myDelegate;
public MyClass()
{
//myDelegate = new MyDelegate(Printf1); 原始创建委托对象的方式
myDelegate = Printf1;
myDelegate += Printf2;
}
}
delegate void MyDelegate(int x);
在类MyClass的构造函数中实例化了委托MyDelegate并绑定了两个方法Printf1、Printf2,这
里实例化(即创建委托类型的对象)有两种方法,一种是注释里面的用new操作符,这是常规
原始的调用,还一种就是直接用=操作符,这是便捷语法,日常我们一般使用便捷语法注意此
处绑定两个方法分别用了=和+=两个操作符,都是合法的,但并不等效前面说了一个委托可以
持有多个方法,使用+=操作符可以将右边方法加到委托持有的方法的尾端,也就是说如果本
身委托持有了两个方法,再使用+=操作符,该委托便持有了三个方法,如果使用=操作符,该
委托就只持有一个方法了,就是最后等于号右边那个。
接着我实例化MyClass并调用myDelegate委托,代码如下:
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.myDelegate(2);
myClass.myDelegate.Invoke(2);
myClass.myDelegate?.Invoke(2);
Console.Read();
}
}
class MyClass
{
void Printf1(int x)
{
Console.WriteLine(x);
}
void Printf2(int x)
{
Console.WriteLine(x + 1);
}
public MyDelegate myDelegate;
public MyClass()
{
//myDelegate = new MyDelegate(Printf1); 原始创建委托对象的方式
myDelegate += Printf1;
myDelegate = Printf2;
}
}
delegate void MyDelegate(int x);
可以看到委托的调用方法有三种,一种像普通方法一样调用,名称后面加括号,括号里面放
传参。
还一种是.Invoke()来调用,还一种?.Invoke来调用。
前两者是等效的,一般情况下没什么问题,但是如果该委托未持有任何方法的时候这样调用
会报错,第三种?.Invoke帮我们包装了一下,调用之前会判断该委托是否持有方法,没有不
调用,有的话调用,这样就不会报错,推荐使用第三种。
上述代码运行结果如下:
可以看到委托被调用了三次,并且每次先进行了Printf1方法,再进行Printf2方法,此顺序与绑定时的先后顺序相同
C#定义好了一些常用的委托,比如泛型委托Func<>和Action<>,传参类型如下,合适的时候直接使用即可,不用自己定义
- Func<TResult>
- Func<T,TResult>
- Func<T1,T2,TResult>
- Func<T1,T2,T3,TResult>
- Func<T1,T2,T3,T4,TResult>
- Action
- Action<T>
- Action<T1,T2>
- Action<T1,T2,T3>
- Action<T1,T2,T3,T4>