前言
打算整理c# 代码简化史系列,所以相关的整理一下。
什么是委托,官网这样介绍。
同样委托有下面属性:
委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。 在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。 你可以通过委托实例调用方法。
委托类似于 C++ 函数指针,但委托完全面向对象,不像 C++ 指针会记住函数,委托会同时封装对象实例和方法。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不必与委托类型完全匹配。
C# 2.0 版引入了匿名方法的概念,可以将代码块作为参数(而不是单独定义的方法)进行传递。 C# 3.0 引入了 Lambda 表达式,利用它们可以更简练地编写内联代码块。 匿名方法和 Lambda 表达式(在某些上下文中)都可编译为委托类型。 这些功能现在统称为匿名函数。
正文
下面就一以来介绍下面的属性吧。
第一句怎么理解呢?委托是一种引用类型,表示对具有特定参数列表和返回类型的方法的引用。
举个例子:
public delegate int PerformCalculation(int x, int y);
class Program
{
public delegate int PerformCalculation(int x, int y);
static void Main(string[] args)
{
PerformCalculation p = new PerformCalculation(add);
}
public static int add(int x, int y)
{
return x + y;
}
}
public delegate int PerformCalculation(int x, int y) 是定义了一个委托类型,然后呢,我们可以实例化它。
我们可以实例化传入对应的方法,而不是传入x和y,这是和普通实例不一样的,初学的时候可以理解为对方法的封装。
那么调用的时候就是 p.Invoke(1,2);,通过invoke方法来调用,当然也可以p()来调用,这是语法糖。
p.invoke 会触发当前封装好的方法,其实本质是指针,这个后续系列中会展示。
第二句话,其实本质就是指针哈,只是对其进行了封装,后续系列。
第三句话,如下:
public static int hasCallBack(PerformCalculation performCalculation)
{
return performCalculation.Invoke(1,2);
}
第四句话:委托可以链接在一起;
PerformCalculation p = new PerformCalculation(add);
PerformCalculation p2 = new PerformCalculation(sub);
p += p2;
也可以简写:
p += sub; 本质一致,只是操作自定义里面做的判断类型了。在c#1版本中用的还是方法连接,现在版本中删除了。
同样PerformCalculation p =add;这是可以这样写。
那么这里有一个问题,既然可以连接多个委托,那么返回的结果是哪个呢?返回的是最后一个结果,如果运行正常得到话,如果不正确会报错,且当前运行方法后面的不会运行,这也是使用委托非常值得关注的地方。
第五句话 方法不必与委托类型完全匹配
这个指的是逆变和协变
协变:
本示例演示如何将委托与具有返回类型的方法一起使用,这些返回类型派生自委托签名中的返回类型。 DogsHandler 返回的数据类型属于 Dogs 类型,它派生自委托中定义的 Mammals 类型。
发一个官网的例子:
class Mammals {}
class Dogs : Mammals {}
class Program
{
// Define the delegate.
public delegate Mammals HandlerMethod();
public static Mammals MammalsHandler()
{
return null;
}
public static Dogs DogsHandler()
{
return null;
}
static void Test()
{
HandlerMethod handlerMammals = MammalsHandler;
// Covariance enables this assignment.
HandlerMethod handlerDogs = DogsHandler;
}
}
然后是逆变:
官网例子:
本示例演示如何将委托与具有参数的方法一起使用,这些参数的类型是委托签名参数类型的基类型。 通过逆变可以使用一个事件处理程序而不是多个单独的处理程序。
下面的示例使用两个委托:
public delegate void KeyEventHandler(object sender, KeyEventArgs e)
public delegate void MouseEventHandler(object sender, MouseEventArgs e)
然后可以这样:
// Event handler that accepts a parameter of the EventArgs type.
private void MultiHandler(object sender, System.EventArgs e)
{
label1.Text = System.DateTime.Now.ToString();
}
public Form1()
{
InitializeComponent();
// You can use a method that has an EventArgs parameter,
// although the event expects the KeyEventArgs parameter.
this.button1.KeyDown += this.MultiHandler;
// You can use the same method
// for an event that expects the MouseEventArgs parameter.
this.button1.MouseClick += this.MultiHandler;
}
这里简单说一下逆变和协变的区别,协变是作用域返回值,且是子类 赋值给父类,这看起来很和谐,因为子类继承父类。
逆变就是作用于参数,然后是父类赋值给子类,这其实就有点逆反的作用。
但是如果你们去看il语言你们就不觉得奇怪了,因为他们其实是编译器帮助做了转换,这节只是简单的做下介绍。
然后最后一句是就是后面一章用来汇总的历史的,所以就不介绍了。