本系列文章将详细探讨C#中的委托,列举其主要的实现方式,并分析其在设计层面和编码层面带来的好处,最后会讨论其安全性和执行效率等。
什么是委托?
委托是寻址方法的.NET版本,使用委托可以将方法作为参数进行传递。委托是一种特殊类型的对象,其特殊之处在于委托中包含的只是一个活多个方法的地址,而不是数据。
委托虽然看起来像是一种类型,但其实定义一个委托,是定义了一个新的类。下面这行代码,定义了一个委托,使用ILDasm.exe查看其生成的IL代码如图所示:
//定义委托,它定义了可以代表的方法的类型,但其本身却是一个类 public delegate int methodDelegate(string str);
由图中红色框线中可以看出,.NET将委托定义为一个密封类,派生自基类System.MulticastDelegate,并继承了基类的三个方法(稍后讨论这三个)。
委托与函数指针的区别
1、安全性:C/C++的函数指针只是提取了函数的地址,并作为一个参数传递它,没有类型安全性,可以把任何函数传递给需要函数指针的地方;而.NET中的委托是类型安全的。
2、与实例的关联性:在面向对象编程中,几乎没有方法是孤立存在的,而是在调用方法前通常需要与类实例相关联。委托可以获取到类实例中的信息,从而实现与实例的关联。
3、本质上函数指针是一个指针变量,分配在栈中;委托类型声明的是一个类,实例化为一个对象,分配在堆中。
4、委托可以指向不同类中具有相同类型返回参数和签名的函数,函数指针则不可以。
namespace ConsoleApplication1 { //定义委托,它定义了可以代表的方法的类型,但其本身却是一个类 public delegate void methodDelegate(string str); class Program { static void Main(string[] args) { Student student = new Student(); Teacher teacher = new Teacher("王老师"); methodDelegate methodDelegate1 = new methodDelegate(student.getStudentName); methodDelegate1 += teacher.getTeacherName; //可以指向不同类中的方法! //methodDelegate1 += teacher.getClassName; 指向签名不符的方法时提示错误! methodDelegate1.Invoke("张三"); Console.ReadLine(); } } class Student { private String name = ""; public Student (String _name) { this.name = _name ; } public Student() {} public void getStudentName(String _name) { if (this.name != "" ) Console.WriteLine("Student's name is {0}", this.name); else Console.WriteLine("Student's name is {0}", _name); } } class Teacher { private String name; public Teacher(String _name) { this.name = _name; } public void getTeacherName(String _name) { if (this.name != "") Console.WriteLine("Teacher's name is {0}", this.name); else Console.WriteLine("Teacher's name is {0}", _name); } public string getClassName() { return "Eanlish"; } } }
上述测试代码运行结果如下:
当指向签名不符的方法时会提示如下错误,证实了委托的安全性。
本篇结束,下一篇介绍委托的主要实现方式。