读书笔记(委托)
委托回调静态方法和实例方法有何区别
- 当委托绑定静态方法时,内部的对象成员变量_target会被设置成null
- 当委托绑定实例方法是,_target将会设置成指向该实例方法所属的一个实例对象
- 当委托被执行时,该对象实例将会用来调用实例方法
1 class DelegateReturn 2 { 3 public delegate String GetStringDelegate(); 4 5 static string GetTypeName() 6 { 7 return typeof(DelegateReturn).ToString(); 8 } 9 static string GetTimeString() 10 { 11 return DateTime.Now.ToString(); 12 } 13 static void TestDelegate() 14 { 15 GetStringDelegate _myDelegate = new GetStringDelegate(GetTimeString); 16 _myDelegate += GetTypeName; 17 18 _myDelegate(); 19 //1只有一个返回值,GetTypeName返回值 20 foreach (Delegate d in _myDelegate.GetInvocationList()) 21 Console.WriteLine(d.DynamicInvoke()); 22 //2会有两个返回值 23 } 24 }
链式委托的执行顺序是:按照委托链上的顺序从当前委托开始一次往后执行,如果有需要,可以通过GetInvocationList()方法来获得委托链上所有需要执行的委托,并且按照任何希望的顺序去执行它们。
在上述第二种方法中,委托链中每个方法的返回值都不会丢失
委托可以是带有返回值的方法,但多于一个带返回值的方法被添加到委托链中时,程序员需要受到地调用委托链上的每个方法,否则委托使用者将只能得到委托链上最后一个被执行方法的返回值
1 /// <summary> 2 /// 自定义一个事件类型参数 3 /// </summary> 4 public class ConsoleEventArgs : EventArgs 5 { 6 private string _message; 7 public ConsoleEventArgs():base() 8 { 9 _message = String.Empty; 10 } 11 public ConsoleEventArgs(string message) :base() 12 { 13 _message = message; 14 } 15 public string Message 16 { 17 get 18 { 19 return _message; 20 } 21 } 22 } 23 24 /// <summary> 25 /// 管理控制台,在输出前发出输出事件 26 /// </summary> 27 public class ConsoleEventManager 28 { 29 //定义控制台事件成员对象 30 public event EventHandler<ConsoleEventArgs> ConsoleEvent; 31 /// <summary> 32 /// 控制台输出 33 /// </summary> 34 /// <param name="message">用来构造事件参数</param> 35 public void ConsoleOutput(string message) 36 { 37 ConsoleEventArgs args = new ConsoleEventArgs(message); 38 } 39 /// <summary> 40 /// 负责发送事件 41 /// </summary> 42 /// <param name="args">事件参数</param> 43 public virtual void SendConsoleEvent(ConsoleEventArgs args) 44 { 45 //定义一个临时的引用变量,这样可以确保多线程访问时不会发生问题 46 EventHandler<ConsoleEventArgs> temp = ConsoleEvent; 47 if(temp != null) 48 { 49 temp(this,args); 50 } 51 } 52 } 53 /// <summary> 54 /// 日志类型,订阅控制台输出事件 55 /// </summary> 56 public class Log 57 { 58 private const String LogFile = "C:\\TestLog.txt"; 59 public Log(ConsoleEventManager cm) 60 { 61 //订阅控制台输出事件 62 cm.ConsoleEvent += WriteLog; 63 } 64 /// <summary> 65 /// 事件处理方法,注意参数固定模式 66 /// </summary> 67 /// <param name="sender">事件发送者</param> 68 /// <param name="args">事件参数</param> 69 private void WriteLog(object sender,EventArgs args) 70 { 71 if(!File.Exists(LogFile)) 72 { 73 using(FileStream fs = File.Create(LogFile)){} 74 } 75 FileInfo info = new FileInfo(LogFile); 76 using(StreamWriter sw = info.AppendText()) 77 { 78 sw.WriteLine(DateTime.Now.ToString()+"|"+sender.ToString()+"}"+((ConsoleEventArgs)args).Message); 79 } 80 } 81 }
- 定义了事件使用的参数类型 ConsoleEventArgs
- 定义了事件类型的私有成员 ConsoleEventManager.ConsoleEvent
- 定义了事件发送的方法 ConsoleEventManager.SendConsoleEvent
- 订阅事件 Log类型
当程序执行时,ConsoleEventManager类型负责在控制台输出测试字符串,同时,订阅了控制台输出事件的Log类型会在日志文件中写入同样的内容
事件是一种使用对象或者类能够通过提供通知的成员,客户端可以通过提供事件处理为相应的事件添加可执行代码,事件是一种特殊的委托
事件是一个委托类型,该委托类型的方法无返回值,并且拥有两个参数,object TEventArg
事件的订阅和取消都是基于委托链表来实现的