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)
        {

        }
    }
    
}
Example
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;
        }
    }
}
DelegateDemo

 

 多播委托

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}");
        }
    }
}
自定义标准事件

 

posted @ 2021-02-08 22:48  KnowledgePorter  阅读(69)  评论(0)    收藏  举报