CSharp 委托(delegate)学习笔记

委托(delegate)

1、委托是什么

委托是一种表示对具有特定参数列表和返回类型的方法的 引用类型 。实例化委托时,可以将其实例与具有 兼容签名返回类型 的任何方法相关联。可以通过委托实例调用(或调用)方法。 从官网咱们可以看到委托的定义,明确了下面这几点:

  1. 委托是一种引用类型,这意味着,委托是和类(class)、枚举类型 (enum)、结构体(struct)同等级别的存在,其作用都是定义了一种类型。
  2. 委托实例可以和具有相同签名的 兼容签名 和 返回类型 的 任何方法 相关联

这第二点可能是比较难理解的,所以我们先看看下面这一段代码之后再来解释:

/// 在此我们定义了一个名叫MyDelegate的委托类型
/// 其返回值为int类型,而参数列表中有两个分别名为a和b的int类型的参数
delegate int MyDelegate(int a,int b);

class Test{
	/// 在Test类中包含了一个名为myDelelgate的MyDelegate类型实例    
	MyDelegate myDelegate;
    public Test(MyDelegate mDelegate){
    	/// 在Test类中的构造方法中赋予myDelegate值
        myDelegate = mDelegate;
    }
    /// 通过Test类中的Invoke方法里像调用方法一样使用myDelegate
    public int Invoke(int a,int b){
        return myDelegate(a,b);
    }
    
    public static int Add(int a,int b){
        return a+b;
    }
    /// 为了说明某个要点,构建了一个名为InnerClass的内部类
    /// 该类只有一个方法
    public class InnerClass{
    	public int Plus(int a,int b){
        	return a*b;
    	}
	}
	
    public static void Main(){
    	/// 使用静态方法Add作为参数构造一个Test实例
    	Test test1 = new Test(new MyDelegate(Add));
    	/// 使用InnerClass类的实例方法Plus作为参数构造一个Test实例
    	Test test2 = new Test(new InnerClass().Plus);
    	/// 分别输出两个实例Invoke方法的结构
    	Console.WriteLine(test1.Invoke(1,2));
    	Console.WriteLine(test2.Invoke(1,2));
    	Console.ReadKey();
    }
}

阅读了这段代码之后,我们其实就能够比较清楚的理解上面第二点了:

  • 委托实例可以和具有相同签名的 兼容签名返回类型任何方法 相关联。 首先是关键词 兼容签名 这里的签名主要指的是方法的参数列表的参数个数、参数类型要兼容,这里的兼容目前理解为一致即可。 (若要深入理解的话,可以了解C#的协变性与逆变性) 再是关键词 返回类型 其实与签名一致,也需要是兼容的返回类型。 后是关键词 任何方法 ,这里的任何指的意思就是说包括静态方法和实例方法,在 上述代码中我们举了Add静态方法和Plus实例方法为例说明了这一要点。 也就是说,当方法满足了这三个条件后,我们便可以将这个方法来当成一个委托实例来使用(事实上是进行了类型转换),或者使用这个方法来生成一个委托实例。虽然说,委托的定义和一些规矩咱们已经清楚了。

2.那么委托可以用来干什么呢?

委托可以节省很多重复的代码,并且让之前写的代码得以复用。从面对对象的角度来理解,委托实例即是将一个方法当作一个对象来看待,我们可以通过传递委托实例,来动态的改变某个地方的逻辑,而使得其他的代码复用。 这和面向对象中的多态会有些类似。 事实上,委托有些时候是可以用多态来替代的,但是多态需要继承,也就是说,如果使用多态来实现的话,那么我们有时候需要写好几个类, 很明显这是一个比较麻烦的事情,是一种很不方便的方式。 而使用委托的话,就不需要再弄几个新的类, 而只需要写几个新的方法即可,甚至还有更简单的方式,也就是接下来我们会提到的lambda表达式。

3.lambda表达式

上文提到,如果要使用委托的话,往往都会使用一个方法来转换成一个委托实例。然而,如果每弄一个别的委托实例都需要新建一个方法的话,存在以下问题:

  1. 起名字困难,有时候我们可能会对相似的方法取名为类似于CMP1,CMP2,CMP3这样的形式,很难以起一个形象的好名字。
  2. 要转换成委托实例的方法不一定会被作为委托实例以外别处调用,一个类会因此多一个我们很少用到的方法。 为了解决这些问题,简化编程,有一种语法叫做lambda表达式。

比如对于上述的Plus方法我们就可以用下面这段lambda表达式替代:

MyDelegate Plus = (a,b) => (a*b);

有兴趣的同学可以翻阅官网或者其他博客了解,这里就不多赘述了。

你可能感兴趣的:(C#)