委托、事件 茴字有几种写法
作用
可以将方法作为变量
委托与事件最大的作用其实就是可以让方法(函数)成为一个变量,然后再外部实例化这个类时定义这个方法。但是方法不属于基本类型,不能像定义普通变量一样的去声明它,如我们可以定义一个速度变量
public int speed{get;set;}
。但是不能定义一个方法
public 求距离的方法 GetDistince{get;set;}
我们需要先定义个委托类型 public delegate void 求距离的方法(DateTime dt);
然后才可以写 public 求距离的方法 GetDistince;
这样就很麻烦,微软为了解决这个问题就发明了事件、和预定义了Action<> Func<>等委托。然后为了简化事件的写法。接着发明了 事件.Invoke 等方法。所以现在,我们要想将一个类的方法在实例化时定义,就有很多种写法。
不用委托的代码
public static void main() { console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的事"); }
封装
后面我发现其他地方也要用到相同的功能,所以我想封装下,将程序要做的事写在另一个类中。
public static void main() { common.DoSomeThing(); } public class common { public static void DoSomeThing() { Console.Write("程序要做的事"); Console.Write("程序要做的事"); Console.Write("程序要做的事"); Console.Write("程序要做的事"); } }
委托解决的问题:方法可变,可能有多个类似的方法
然后我们发现程序要做的事有部分不一样,所以我们希望由main函数可以设置doSomeThing中执行什么函数。
我们用到的可能doSomeThing可能有下面两个版本
public static void DoSomeThing1() { console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的特殊事情1"); } public static void DoSomeThing2() { console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的事"); console.write("程序要做的特殊事情2"); }
使用委托
这样就很不好看,也不利于扩展,所以可以引入委托,这样我们可以在执行的时候自己选择执行什么特殊方法。
class Program { static void Main(string[] args) { //指定特殊的那段程序执行什么 common.doSomeThingSpeical += common.DoSomeThingSpeical1; common.DoSomeThing(); } } public class common { public delegate void DoSomeThingSpeicaldelegate(); public static DoSomeThingSpeicaldelegate doSomeThingSpeical; public static void DoSomeThing() { Console.Write("程序要做的事"); Console.Write("程序要做的事"); Console.Write("程序要做的事"); if (doSomeThingSpeical != null) { doSomeThingSpeical(); } Console.ReadKey(); } public static void DoSomeThingSpeical1() { Console.Write("程序要做的独特的事1"); } public static void DoSomeThingSpeical2() { Console.Write("程序要做的独特的事2"); } }
如果既不想用DoSomeThingSpeical1也不想用DoSomeThingSpeical2,那么可以在调用的时候自己写一个DoSomeThingSpeical3,然后给common.doSomeThingSpeical赋值。
class Program { static void Main(string[] args) { //指定特殊的那段程序执行什么 common.doSomeThingSpeical += DoSomeThingSpeical3; common.DoSomeThing(); } public static void DoSomeThingSpeical3() { Console.Write("程序要做的独特的事3"); } }
以上就是委托的基本使用了
预定义的委托
可以看到,我们要将方法作为变量时,需要先定义一个委托,很麻烦,所以微软后来为我们预定义了一些委托(Action Func 等),我们不用声明这个委托就可以直接用他们做变量。
如,上面我们写的:
public delegate void DoSomeThingSpeicaldelegate();
public static DoSomeThingSpeicaldelegate doSomeThingSpeical;
可以直接简化为:
public static Action doSomeThingSpeical;
同样这个也可以写成event的形式,事件的实现要稍微复杂一点,这个例子虽然能改成event的形式,但是说明不了event的应用场景,对event我还需要深入学习体会。
匿名方法
仔细想了下,我觉得还是要先说说匿名方法
在上面的例子中,我们Main函数定义委托时,我们不想定义一个方法,再赋值,这时就可以用匿名方法,直接就可以写方法体而不需要申明这个方法。
class Program { static void Main(string[] args) { //指定特殊的那段程序执行什么 common.doSomeThingSpeical += delegate(){ Console.Write("程序要做的独特的事3"); }; common.DoSomeThing(); } //public static void DoSomeThingSpeical3() //{ // Console.Write("程序要做的独特的事3"); //} }
事件
class Program { static void Main(string[] args) { var Test = new Test(); void eventHandler(object s, EventArgs e) { Console.WriteLine("1"); } void eventHandler2(object s, EventArgs e) { Console.WriteLine("2"); } void eventHandler3(object s, EventArgs e) { Console.WriteLine("3"); } void eventHandler4(object s, EventArgs e) { Console.WriteLine("4"); } //添加事件 Test.A += eventHandler; Test.EventHandlers.Add(eventHandler2); Test.Actions.Add(eventHandler3); Test.B += eventHandler4; Test.Run(); //移除事件 Test.A -= eventHandler; Test.EventHandlers.Remove(eventHandler2); Test.Actions.Remove(eventHandler3); Test.B -= eventHandler4; Console.ReadKey(); } } public class Test { public List<EventHandler> EventHandlers { get; set; } = new List<EventHandler>(); public event EventHandler A { add { EventHandlers.Add(value); } remove { EventHandlers.Remove(value); } } public List<Action<object, EventArgs>> Actions { get; set; } = new List<Action<object, EventArgs>>(); public event Action<object, EventArgs> B { add { Actions.Add(value); } remove { Actions.Remove(value); } } public void Run() { EventArgs e = new EventArgs(); foreach (var eventHandler in EventHandlers) { eventHandler.Invoke("Test", e); } foreach (var action in Actions) { action.Invoke("Test2", e); } } }