• 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");
  • 相关阅读:
    初解DLL基本知识
    读《暗时间》笔记
    红队 Cobalt Strike 安全加固
    《天书夜读 —— 从汇编语言到Windows内核编程》3.3 汇编反C语言练习 参考答案
    记录一次从WordPress后台到拿下主机shell的渗透
    今日记 2019.6.19
    解决Termux无法通过metasploit.sh安装Metasploit的问题
    解决ajax中文乱码问题
    jsp开发知识
    第一个Java web项目:员工管理系统
  • 原文地址:https://www.cnblogs.com/z888/p/5798871.html
Copyright © 2020-2023  润新知