C# 委托、lambda表达式和事件 (7) 持续更新
引用方法
在C++,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。
C# 委托 定义了返回类型和参数的类型。委托类包含对方法的引用,还可以包含多个方法引用。
定义委托
public delegate double TwoLongsOp(long first, long second); public delegate string GetAString();
委托派生自 System.MulticastDelegate,而 System.MulticastDelegate 又派生自 System.Delegate。
public delegate string GetAString(); static void Main(string[] args) { int x = 10; Console.WriteLine(x.ToString()); GetAString stringFun = new GetAString(x.ToString); Console.WriteLine(stringFun()); } // 以下两种方法一样 stringFun(); stringFun.Invoke();
GetAString stringFun = new GetAString(x.ToString); GetAString stringFun2 = x.ToString;
委托它们类型是安全的,可以确保被调用的方法的签名是正确的。但它们不关心什么类型的对象上调用该方法,甚至不考虑该方法是静态方法,还是实例方法。
class MyClass { public static string getStr() { return "Hello"; } } static void Main(string[] args) { GetAString stringFun = MyClass.getStr; Console.WriteLine(stringFun()); }
委托数组
GetAString[] stringFun = { MyClass.getStr }; Console.WriteLine(stringFun[0]());
泛型 Action<T> 委托表示引用一个 void 返回类型的方法。Action 可以调用 0 ~ 16 个参数的方法。
Func<T> 引用 带 返回类型的方法,Func可以调用 0 ~ 16 个参数的方法。
class MyClass { public static string getString(string s) { return "Hello "+ s; } public static void Call() { Console.WriteLine("Hello Call"); } } static void Main(string[] args) { Func<string, string> stringFun = MyClass.getString; Console.WriteLine(stringFun("Wo")); Action fun2 = MyClass.Call; fun2(); }
多播委托
存储两个方法的引用
增加 += 删除 -=
class MyClass { public static void Hello(string s) { Console.WriteLine("Hello " + s); } public static void Call(string s) { Console.WriteLine("Call " + s); } } static void Main(string[] args) { Action<string> action = MyClass.Hello; action += MyClass.Call; action("Zhao"); action -= MyClass.Call; action("Zhao2"); }
如果 Hello 方法报错了,第二个 Call 就不会执行了。可以用以下代替。
Action<string> action = MyClass.Hello; action += MyClass.Call; Delegate[] delegates = action.GetInvocationList(); foreach (Action<string> action2 in delegates) { try { action2("Python"); } catch (Exception) { } }
匿名方法
Action<string> action = delegate(string str) { Console.WriteLine("Anonymous " + str); }; Delegate[] delegates = action.GetInvocationList(); foreach (Action<string> action2 in delegates) { try { action2("Python"); } catch (Exception) { } }
匿名方法不能使用跳转语句(break、goto 或 continue)跳到该匿名方法的外部。匿名方法内部能访问不安全的代码。也不能使用 ref 和 out 参数。但可以使用匿名方法外部定义的其他变量。
lmadba
Action<string> action = str => Console.WriteLine("lambda " + str); Action<string> action2 = (str) => { Console.WriteLine("lambda " + str); };
匿名方法
int sum = 12; Func<int, int> fun = x => x + sum; Console.WriteLine(fun(12) + " " + sum);
事件
class Program { public class CustomEventArgs : EventArgs { public CustomEventArgs(string car) { this.Car = car; } public string Car { get; private set; } } public static event EventHandler<CustomEventArgs> NewEvent; static void Main(string[] args) { NewEvent += NewEventHandler; NewEvent += NewEventHandler; NewEvent -= NewEventHandler; CustomEventArgs eventArgs = new CustomEventArgs("Audio"); NewEvent(null, eventArgs); } static void NewEventHandler(object sender, CustomEventArgs e) { Console.WriteLine("事件处理参数 " + e.Car); } }
NewEvent += NewEventHandler; // 添加事件 NewEvent -= NewEventHandler; // 移除事件
弱事件
在不需要使用事件时,需要移除事件。否则的话,会出现内存泄露。另一种方法用弱事件。
public class WeakCarInfoEventManager : WeakEventManager { public static void AddListener(object source, IWeakEventListener listener) { CurrentManager.ProtectedAddListener(source, listener); } public static void RemoveListener(object source, IWeakEventListener listener) { CurrentManager.ProtectedRemoveListener(source, listener); } public static WeakCarInfoEventManager CurrentManager { get { WeakCarInfoEventManager manager = GetCurrentManager(typeof(WeakCarInfoEventManager)) as WeakCarInfoEventManager; if (manager == null) { manager = new WeakCarInfoEventManager(); SetCurrentManager(typeof(WeakCarInfoEventManager), manager); } return manager; } } protected override void StartListening(object source) { (source as CarDealer).NewCarInfo += CarDealer_NewCarInfo; } void CarDealer_NewCarInfo(object sender, CarInfoEventArgs e) { DeliverEvent(sender, e); } protected override void StopListening(object source) { (source as CarDealer).NewCarInfo -= CarDealer_NewCarInfo; } }
侦听
var dealer = new CarDealer(); var michael = new Consumer("Michael"); WeakCarInfoEventManager.AddListener(dealer, michael); dealer.NewCar("Mercedes"); var sebastian = new Consumer("Sebastian"); WeakCarInfoEventManager.AddListener(dealer, sebastian); dealer.NewCar("Ferrari"); WeakCarInfoEventManager.RemoveListener(dealer, michael); dealer.NewCar("Red Bull Racing");
还可以用内置的 泛型弱事件 写的代码更少
var dealer = new CarDealer(); var michael = new Consumer("Michael"); WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", michael.NewCarIsHere); dealer.NewCar("Mercedes"); var sebastian = new Consumer("Sebastian"); WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", sebastian.NewCarIsHere); dealer.NewCar("Ferrari"); WeakEventManager<CarDealer, CarInfoEventArgs>.RemoveHandler(dealer, "NewCarInfo", michael.NewCarIsHere); dealer.NewCar("Red Bull Racing");