delegate void StringPRocessor(string input);
其中的StringProcessor是一个类型。
2.定义签名相同的方法定义的方法要与委托有类型相同的返回值和参数。private void GetStringLength(object x){} //C#2.0以后认为一致
3.创建委托实例
创建委托实例就是指定在调用委托实例时执行的方法。StringProcessor proc1,proc2//GetStringLength 实例方法proc1= new StringProcessor(GetStringLength);//GetString 静态方法proc2 += GetString;
4.调用委托 调用委托就是调用一个委托实例方法。
proc1("Hello World");
具体的示例代码:
namespace Program { //定义委托 delegate void StringProcessor(string input); class Person { string name; public Person(string name) { this.name = name; } //定义与委托签名相同的"方法" public void Say(string message) { Console.WriteLine(name+" say:" + message); } } class BackGround { //定义与委托签名相同的"静态方法" public static void Note(string note) { Console.Write("{0}", note); } } class Program { static void Main(string[] args) { Person jon = new Person("Jom"); Person tom = new Person("Tom"); //创建委托实例(第一步) StringProcessor proc1, proc2, proc3; //创建委托实例:赋值(第二部) proc1 = new StringProcessor(jon.Say); proc2 = new StringProcessor(tom.Say); proc3 = BackGround.Note; //调用委托 proc1("Hello jon"); proc2("Hello tom"); proc3("note"); Console.ReadKey(); } }}书中的代码示例:
namespace Test{ // 1.声明委托类型 internal delegate void Feedback(Int32 value); internal class Program { private static void Main(string[] args) { StaticDelegateDemo(); InstanceDelegateDemo(); ChainDelegateDemo1(new Program()); ChainDelegateDemo2(new Program()); } private static void StaticDelegateDemo() { Console.WriteLine("----- Static Delegate Demo -----"); Counter(1, 3, null); // 3.创建委托实例 Counter(1, 3, new Feedback(Program.FeedbackToConsole)); Counter(1, 3, new Feedback(FeedbackToMsgBox)); Console.WriteLine(); } private static void InstanceDelegateDemo() { Console.WriteLine("----- Instance Delegate Demo -----"); Program di = new Program(); // 3.创建委托实例 Counter(1, 3, new Feedback(di.FeedbackToFile)); Console.WriteLine(); } private static void ChainDelegateDemo1(Program di) { Console.WriteLine("----- Chain Delegate Demo 1 -----"); // 3.创建委托实例 Feedback fb1 = new Feedback(FeedbackToConsole); Feedback fb2 = new Feedback(FeedbackToMsgBox); Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null; fbChain = (Feedback)Delegate.Combine(fbChain, fb1); fbChain = (Feedback)Delegate.Combine(fbChain, fb2); fbChain = (Feedback)Delegate.Combine(fbChain, fb3); Counter(1, 2, fbChain); Console.WriteLine(); fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox)); Counter(1, 2, fbChain); } private static void ChainDelegateDemo2(Program di) { Console.WriteLine("----- Chain Delegate Demo 2 -----"); Feedback fb1 = new Feedback(FeedbackToConsole); Feedback fb2 = new Feedback(FeedbackToMsgBox); Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null; fbChain += fb1; fbChain += fb2; fbChain += fb3; Counter(1, 2, fbChain); Console.WriteLine(); fbChain -= new Feedback(FeedbackToMsgBox); Counter(1, 2, fbChain); } private static void Counter(Int32 from, Int32 to, Feedback fb) { for (Int32 val = from; val <= to; val++) { // 如果指定了任何回调,就可以调用它 if (fb != null) // 4.调用委托 fb(val); } } // 2.声明签名相同的方法 private static void FeedbackToConsole(Int32 value) { Console.WriteLine("Item=" + value); } // 2.声明签名相同的方法 private static void FeedbackToMsgBox(Int32 value) { Console.WriteLine("Item=" + value); } // 2.声明签名相同的方法 private void FeedbackToFile(Int32 value) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Item=" + value); sw.Close(); } }}二、用委托回调静态方法在上面的代码中,我们可以清楚的看到用委托如何回调静态方法。直接将静态方法绑定到委托的实例上,再通过实例进行调用。将一个方法绑定到一个委托时,C#和CLR都允许引用类型的协变性和逆变性。协变性是指方法能返回从委托的返回类型派生的一个类型。逆变性是指方法获取的参数可以是委托的参数类型的基类。例如下面的委托:
deleget Object MyCallback(FileStream s);
完全可以构造该委托类型的一个实例,并和具有一下原型的一个方法绑定:
String SomeMethod(Stream s);
在这里,SomeMethod的返回类型(String)派生自委托的返回类型(Object);这种协变性是允许的。SomeMethod的参数类型(Stream)是委托的参数类型(FileStream)的基类;这种逆变性是运行部的。
注意,协变性和逆变性只能用于引用类型,不能作用于值类型和void。所以下面示例是错误的:Int32 SomeMethod(Stream s);//这是错误的
值类型和void之所以不支持协变性和逆变性,是因为它们的存储结构是变化的,而引用类型的存储结构始终是一个指针。
三、用委托回调实例方法使用委托回调实例方法,在上面代码中演示已经非常清楚了,就不细说了。四、委托揭秘从表面看,委托似乎很容易使用:用C#的delegate关键字声明,用熟悉的new操作符构造委托实例,用熟悉的方法调用语法来调用回调函数。然而,实际情况远比前面例子演示的复杂的多。编译器和CLR在幕后做了大量工作来隐藏复杂性。本节重点讲解了编译器和CLR如何协同工作来实现委托。首先让我们重写审视下面的代码:internal delegate void Feedback(Int32 value);
看到这行代码,编译器实际会像下面这样定义一个完整的类:
internal class Feedback: System.MulticastDelegate { // 构造器 public Feedback(Object object, IntPtr method); // 这个方法和源代码指定的原型一样 public virtual void Invoke(Int32 value); // 以下方法实现了对回调方法的异步回调 public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object object); public virtual void EndInvoke(IAsyncResult result);}
编译器定义的类有4个方法:一个构造器、Invoke、BeginInvoke和EndInvoke。本节重点解释构造器和Invoke,BeginInvoke和EndInvoke看留到后面讲解。
事实上,可用ILDasm.exe查看生成的程序集,验证编译器真的会自动生成这个类,如图17-1所示:字段 | 类型 | 说明 |
_target | System.Object | 当委托对象包装一个静态方法时,这个字段为null。当委托对象包装一个实例方法时,这个字段引用的是回调方法要操作的对象。换言之,这个字段指出了要传给实例方法的隐式参数this的值 |
_methodPtr | System.IntPtr | 一个内部的整数值,CLR用它来标识要回调的方法 |
_invocationList | System.Object | 该字段通常为null。构造一个委托链时,它可以引用一个委托数组。 |
Feedback fbStatic = new Feedback(Program.FeedbackToConsole)
新闻热点
疑难解答