C# 委托(泛型委托、多播委托、委托事件、自定义标准事件)
.NET库里很多涉及委托
委托是一个类型,保存的是方法的指针,指向一个方法。调用委托的时候,方法就立即执行。

using System; namespace DelegateDemo { class Program { delegate void HelloDelegate(string msg); static void Main(string[] args) { Console.WriteLine("Hello World!"); HelloDelegate helloDelegate = new HelloDelegate(Hello);//创建委托实例 helloDelegate("你好委托");//使用委托 } public static void Hello(string str) { Console.WriteLine(str); } } }
委托调用:
delegateObj(args);
delegrateObj.Invoke(args);
为什么要有委托:

namespace DelegateDemo { class Program { delegate void HelloDelegate(string msg); static void Main(string[] args) { /*Console.WriteLine("Hello World!"); HelloDelegate helloDelegate = new HelloDelegate(Hello);//创建委托实例 helloDelegate("你好委托");//使用委托*/ List<LearnVIP> learnVIPs = new List<LearnVIP>(); learnVIPs.Add(new LearnVIP() { id = 1, sn = "mike", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 2, sn = "mike1", Price = 599 }); learnVIPs.Add(new LearnVIP() { id = 3, sn = "mike2", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 4, sn = "mike3", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 5, sn = "mike4", Price = 355 }); LearnVIP.CsharpVip(learnVIPs); } public static void Hello(string str) { Console.WriteLine(str); } } class LearnVIP { public int id { get; set; } public string sn { get; set; } public int Price { get; set; } public static void CsharpVip(List<LearnVIP> learnVIPs) { foreach(LearnVIP learnVIP in learnVIPs) { if(learnVIP.Price==599) { Console.WriteLine(learnVIP.sn + "是vip"); } } } } }
当需要改变vip价格的时候需要改动LearnVIP类的代码。

using System; using System.Collections.Generic; namespace DelegateDemo { class Program { static void Main(string[] args) { List<LearnVIP> learnVIPs = new List<LearnVIP>(); learnVIPs.Add(new LearnVIP() { id = 1, sn = "mike", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 2, sn = "mike1", Price = 599 }); learnVIPs.Add(new LearnVIP() { id = 3, sn = "mike2", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 4, sn = "mike3", Price = 355 }); learnVIPs.Add(new LearnVIP() { id = 5, sn = "mike4", Price = 355 }); IsCSharpVIP isCSharpVIP = new IsCSharpVIP(GetVip); LearnVIP.CsharpVip(learnVIPs,isCSharpVIP); } public delegate bool IsCSharpVIP(LearnVIP learnVIP);//定义委托 public static bool GetVip(LearnVIP learnVIP) { if(learnVIP.Price==599) { return true; }else { return false; } } public class LearnVIP { public int id { get; set; } public string sn { get; set; } public int Price { get; set; } public static void CsharpVip(List<LearnVIP> learnVIPs, IsCSharpVIP isCSharpVIP) { foreach (LearnVIP learnVIP in learnVIPs) { if (isCSharpVIP(learnVIP)) { Console.WriteLine(learnVIP.sn + "是vip"); } } } } } }
本质,把逻辑脱离出来,把一部分代码独立出来,通过委托传递过去。
泛型委托:

namespace DelegateDemo { delegate void GenericDelegrate<T>(T t);//定义委托 class DelegrateDemo { GenericDelegrate<string> genericDelegrate1 = new GenericDelegrate<string>(Method1);//初始化委托 GenericDelegrate<int> genericDelegrate2 = new GenericDelegrate<int>(Method2);//初始化委托 public static void Method1(string str) { } public static void Method2(int i) { } } }

namespace DelegateDemo { class DelegrateDemo { //.Net 预定义的委托 //Action<>指定那些只有输入参数,没有返回值的委托 //Func<> 这个和上面的那个是一样的,区别是这个有返回值! Action<string> action1 = new Action<string>(Method1);//初始化委托 Action<int> action2 = new Action<int>(Method2); Func<string, bool> func = new Func<string, bool>(Method3); public static void Method1(string str) { } public static void Method2(int i) { } public static bool Method3( string str) { return true; } } }
多播委托

namespace Delegrate { delegate void MulticastTest(); /// <summary> /// 多播委托 /// 【1】每个委托都继承自MulticastDelegate,也就是每个都是多播委托 /// 【2】带返回值的多播委托只返回最后一个方法的值 /// 【3】多播委托可以用加减号来操作方法的增加与减少 /// 【4】给委托传递相同的方法时 生成的委托实例也是相同的(也即是同一个委托) /// </summary> class Program { static void Main(string[] args) { //自定义 MulticastTest multicastTest = new MulticastTest(MethodTest); multicastTest(); Action action = new Action(MethodTest); action = (Action)MulticastDelegate.Combine(action, new Action(MethodTest2)); action = (Action)MulticastDelegate.Combine(action, new Action(MethodTest3)); action(); Action action1 = MethodTest; action1 += MethodTest2(); action1 += MethodTest3(); action1 -= MethodTest3(); action1(); foreach(Action action2 in action.GetInvocationList()) { action2(); } Func<string> func = () => { return "我是Lambda"; }; func += () => { return "我是Lambda2"; }; func += () => { return "我是Lambda3"; }; string result = func(); } public static void MethodTest() { } public static void MethodTest2() { } public static void MethodTest3() { } } }
委托事件
【1】定义一个委托
【2】定义调用事件的类
【3】订阅事件
【4】订阅者

namespace Delegrate { /// <summary> /// 委托-事件: /// 事件是委托的安全版本 /// 【1】在定义事件类的外部,不能使用=来操作,只能使用+=. /// 【2】在定义事件类的外部不能调用事件。 /// 【3】事件就是在委托前面增加一个event关键字 /// </summary> delegate void StudentDelegate();//定义委托 class Program { static void Main(string[] args) { EventFunction eventFunction = new EventFunction(); InvokeDefine invokeDefine = new InvokeDefine(); invokeDefine.StudentEvent += eventFunction.Student1; invokeDefine.StudentEvent += eventFunction.Student2; invokeDefine.Invoke(); } /// <summary> /// 定义事件和调用 事件一定要放在一个类里面 /// </summary> class InvokeDefine { public event StudentDelegate StudentEvent; public void Invoke() { StudentEvent?.Invoke();//?. 是带Null检查运算符 } } class EventFunction { public void Student1() { Console.WriteLine("string1"); } public void Student2() { Console.WriteLine("string2"); } } } }
WInform里的事件
public delegate void EventHandler(object sender ,EventArgs e);
public event EventHandler Click;
在 private System.Windows.Forms.Button 对象里定义并调用了事件
自定义标准事件

namespace ConsoleApp1 { class Program { static void Main(string[] args) { Publisher publisher = new Publisher(); Subscriber subscriber = new Subscriber("subscriber", publisher); Subscriber2 subscriber2 = new Subscriber2("subscriber2", publisher); publisher.DoSomething(); Console.ReadKey(); } } //事件参数 public class CustomEventArgs:EventArgs { public CustomEventArgs(string message) { Message = message; } public string Message { get; set; } } /// <summary> /// 事件的发布者 事件的定义和调用,触发事件也可以写在这里面 /// </summary> class Publisher { public event EventHandler<CustomEventArgs> CustomEvent; //在受保护的虚方法中包装事件的调用,这样就允许派生类配重写调用行为 protected virtual void OnCustomEvent(CustomEventArgs e) { CustomEvent?.Invoke(this, e); } public void DoSomething() { //调用之前可以在这里写一些其他的东西 OnCustomEvent(new CustomEventArgs("我是事件参数")); } } /// <summary> /// 事件订阅者:事件方法的编写和订阅 /// </summary> class Subscriber { private readonly string Str; //订阅动作要在这里面了。所以才要传过来发布者 public Subscriber(string str ,Publisher publisher) { Str = str; publisher.CustomEvent += HanderCustomEvent; } private void HanderCustomEvent(object sender ,CustomEventArgs e) { //在这里做想做的事件 Console.WriteLine($"发布者:{sender.GetType()},订阅者:{Str},参数是:{e.Message}"); } } class Subscriber2 { private readonly string Str; //订阅动作要在这里面了。所以才要传过来发布者 public Subscriber2(string str, Publisher publisher) { Str = str; publisher.CustomEvent += HanderCustomEvent; } private void HanderCustomEvent(object sender, CustomEventArgs e) { //在这里做想做的事件 Console.WriteLine($"发布者:{sender.GetType()},订阅者:{Str},参数是:{e.Message}"); } } }