C#委托用法详解
为了实现方法的参数化,C# 提出了委托的概念。
委托是一种引用方法的类型,即委托是方法的引用。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。
委托是面向对象的,相当于函数指针,但不同于函数指针的是委托是类型安全的。C# 支持在回调时或在事件处理时使用委托。
可以使用委托在委托对象的内部封装对某个方法的引用。因为委托是类型安全、可靠的托管对象,所以它既具有指针的所有优点,又避免了指针的缺点。
例如,委托总是指向一个有效的对象,并且不会破坏其他对象所占的内存。
声明委托类型的语法格式如下:
一个与委托类型相匹配的方法必须满足以下两个条件:
委托是方法的类型安全的引用。之所以说委托是安全的,是因为委托和其他所有的 C# 成员一样,是一种数据类型,并且任何委托对象都是 System.Delegate 的某个子类的一个对象。
委托的类结构如下图所示:
图 1 委托的类结构
从图 1 可以看出,任何自定义委托类型都直接继承自 System.MulticastDelegate 类,而 System.Delegate 类是所有委托类的父类。
注意,Delegate 类和 MulticastDelegate 类都是委托类型的父类,但是只有系统和编译器才能从 Delegate 类或 MulticastDelegate 类派生,其他自定义类无法直接继承这两个类。
例如,下面的代码是不合法的。
与所有的对象一样,委托对象也是使用 new 关键字创建的。但是,当创建委托对象时,传递给 new 表达式的参数很特殊,它的写法类似于方法调用,但是不给方法传递参数,而是直接写方法名。一旦委托被创建,它所能关联的方法便固定了,委托对象是不可变的。
当引用委托对象时,委托并不知道也不关心它引用的对象所属的类,只要方法签名与委托的签名相匹配,就可以引用任何对象。
委托既可以引用静态方法,也可以引用实例方法。例如,下面代码声明了一个名为 MyDelegate 的委托,并实例化该委托到一个静态方法和一个实例方法;这两个方法的签名与 MyDelegate 的签名一致,并且返回值都是 void 类型,只有一个 string 类型的参数。
与所有的对象一样,委托对象也是使用 new 关键字创建的。但是,当创建委托对象时,传递给 new 表达式的参数很特殊,它的写法类似于方法调用,但是不给方法传递参数,而是直接写方法名。一旦委托被创建,它所能关联的方法便固定了,委托对象是不可变的。
当引用委托对象时,委托并不知道也不关心它引用的对象所属的类,只要方法签名与委托的签名相匹配,就可以引用任何对象。
委托既可以引用静态方法,也可以引用实例方法。例如,下面代码声明了一个名为 MyDelegate 的委托,并实例化该委托到一个静态方法和一个实例方法;这两个方法的签名与 MyDelegate 的签名一致,并且返回值都是 void 类型,只有一个 string 类型的参数。
1) 服务器对象可以提供一个方法,客户端对象调用该方法为特定的事件注册回调方法。当事件发生时,服务器就会调用该回调函数。通常客户端对象实例化引用回调函数的委托,并将该委托对象作为参数传递。
2) 当一个窗体中的数据变化,与其关联的另外一个窗体中的相应数据需要实时改变时,可以使用委托对象调用第二个窗体中的相关方法实现。
委托是一种引用方法的类型,即委托是方法的引用。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。
委托是面向对象的,相当于函数指针,但不同于函数指针的是委托是类型安全的。C# 支持在回调时或在事件处理时使用委托。
可以使用委托在委托对象的内部封装对某个方法的引用。因为委托是类型安全、可靠的托管对象,所以它既具有指针的所有优点,又避免了指针的缺点。
例如,委托总是指向一个有效的对象,并且不会破坏其他对象所占的内存。
C#委托的声明
C# 中的委托(delegate)是一种引用类型。该引用类型与其他引用类型有所不同,在委托对象的引用中存放的不是对数据的引用,而是对方法的引用,即在委托的内部包含一个指向某个方法的指针。使用委托把方法的引用封装在委托对象中,然后将委托对象传递给调用引用方法的代码。声明委托类型的语法格式如下:
【修饰符】 delegate 【返回值类型】 【委托名称】 (【参数列表】)其中,【修饰符】是可选项;【返回值类型】、关键字 delegate 和【委托名称】是必选项;【参数列表】用来指定委托所匹配的方法的参数列表,所以是可选项。
一个与委托类型相匹配的方法必须满足以下两个条件:
- 这二者具有相同的签名,即具有相同的参数数目,并且类型相同、顺序相同,参数的修饰符也相同;
- 这二者具有相同的返回值类型。
委托是方法的类型安全的引用。之所以说委托是安全的,是因为委托和其他所有的 C# 成员一样,是一种数据类型,并且任何委托对象都是 System.Delegate 的某个子类的一个对象。
委托的类结构如下图所示:
图 1 委托的类结构
从图 1 可以看出,任何自定义委托类型都直接继承自 System.MulticastDelegate 类,而 System.Delegate 类是所有委托类的父类。
注意,Delegate 类和 MulticastDelegate 类都是委托类型的父类,但是只有系统和编译器才能从 Delegate 类或 MulticastDelegate 类派生,其他自定义类无法直接继承这两个类。
例如,下面的代码是不合法的。
public class Test : System.Delegate { } public class Test : System.MulticastDelegate { }下面代码说明了如何对方法声明委托,该方法获取 string 类型的一个参数,并且没有返回类型。
delegate void MyDelegete(string s);
委托的实例化
在声明委托后,就可以创建委托对象,即实例化委托。实例化委托的过程其实就是将委托与特定的方法进行关联的过程。与所有的对象一样,委托对象也是使用 new 关键字创建的。但是,当创建委托对象时,传递给 new 表达式的参数很特殊,它的写法类似于方法调用,但是不给方法传递参数,而是直接写方法名。一旦委托被创建,它所能关联的方法便固定了,委托对象是不可变的。
当引用委托对象时,委托并不知道也不关心它引用的对象所属的类,只要方法签名与委托的签名相匹配,就可以引用任何对象。
委托既可以引用静态方法,也可以引用实例方法。例如,下面代码声明了一个名为 MyDelegate 的委托,并实例化该委托到一个静态方法和一个实例方法;这两个方法的签名与 MyDelegate 的签名一致,并且返回值都是 void 类型,只有一个 string 类型的参数。
委托的实例化
在声明委托后,就可以创建委托对象,即实例化委托。实例化委托的过程其实就是将委托与特定的方法进行关联的过程。与所有的对象一样,委托对象也是使用 new 关键字创建的。但是,当创建委托对象时,传递给 new 表达式的参数很特殊,它的写法类似于方法调用,但是不给方法传递参数,而是直接写方法名。一旦委托被创建,它所能关联的方法便固定了,委托对象是不可变的。
当引用委托对象时,委托并不知道也不关心它引用的对象所属的类,只要方法签名与委托的签名相匹配,就可以引用任何对象。
委托既可以引用静态方法,也可以引用实例方法。例如,下面代码声明了一个名为 MyDelegate 的委托,并实例化该委托到一个静态方法和一个实例方法;这两个方法的签名与 MyDelegate 的签名一致,并且返回值都是 void 类型,只有一个 string 类型的参数。
委托的使用场景
委托的部分使用场景如下。1) 服务器对象可以提供一个方法,客户端对象调用该方法为特定的事件注册回调方法。当事件发生时,服务器就会调用该回调函数。通常客户端对象实例化引用回调函数的委托,并将该委托对象作为参数传递。
2) 当一个窗体中的数据变化,与其关联的另外一个窗体中的相应数据需要实时改变时,可以使用委托对象调用第二个窗体中的相关方法实现。