C#委托/事件

1.委托

1.委托使得一个方法可以作为另一个方法的参数进行传递

2.多播委托

        public delegate int Expression(int a, int b);
        class Program1
        {
            static void Main(string[] args)
            {
                //1.将方法作为参数传递
                Calculate(GetAdd, 25, 10);

                //2.多播委托
                Expression e;
                e = Add;
                e += Divide;
                e(1,2);


            }
            static int Add(int a, int b)
            {
                return a + b;
            }
            static int Divide(int a, int b)
            {
                return a / b;
            }
            static int subtract(int a, int b)
            {
                return a - b;
            }
            static int multiply(int a, int b)
            {
                return a * b;
            }
            static int GetAdd(int a, int b)
            {
                return a + b;
            }
            static void Calculate(Expression ex, int a, int b)
            {
                Console.WriteLine(ex(a, b) + "\n");
            }
        }

https://www.cnblogs.com/wangjiming/p/8300103.html

https://www.cnblogs.com/TJessica/p/6690120.html

https://blog.youkuaiyun.com/u014224380/article/details/82996533

https://blog.youkuaiyun.com/goodshot/article/details/6157529

2.事件

个人理解:
1.多播委托中

                //2.多播委托
                Expression e;
                e = Add;
                e += Divide;
                e = subtract;
                e(1,2);

此时e只会执行subtract,委托链z中断
2.类的外部要给委托赋值和多播委托,则委托定义为public,外部就可以调用委托的实例( a.d(1) ),而一些情况下外部不应该直接调用

        class A
        {
            public delegate void de(int a);
            public de d;

        }
        void fun()
        {
            A a = new A();
            //a.d =new A.de(add);
            a.d =add;
            a.d(1);
        }
        void add(int i)
        {

        }

以上两点引出了事件的概念

事件只需在委托前加event即可:

public event de d;

事件可以理解成一个委托的属性,通过对委托实例的封装来对委托实例的访问进行一些限制

        class T
        {
            private int a;
            public int A{ get; set; }
        }

事件通过IL得出的代码类似


public event AssembleIphoneHandler VerdorToAssembleIphone;

=>

private AssembleIphoneHandler VerdorToAssembleIphone;

public void add_VerdorToAssembleIphone(AssembleIphoneHandler 'value') { }

public void remove_VerdorToAssembleIphone(AssembleIphoneHandler 'value') { }

即事件封装了委托的实例,针对上面两点:
1.event只能+= 或者-= ,在外部不能直接赋值
2.事件只能在内部invoke,外部无法直接调用

  • 在定义事件的类内部,不管你声明它是public还是protected,它总是private的;也就是说在在定义事件的类外部不能对事件进行调用
  • 在定义事件的类外部,添加"+=“和移除”-=“委托实例的访问限定符与声明事件时使用的访问符相同也就是说,如果事件声明为private或这protect,那么定义事件的类外部也不能对事件进行”+=“和”-="操作
        delegate void MyEvent(object sender, CustomEventArgs e);
        public delegate void MyDelegate1(string name);

        class PersonManager
        {

            public event MyEvent Myevent;
            public MyDelegate1 delegate1;

            //执行事件
            public void Execute(CustomEventArgs e)
            {
                MyEvent handler = Myevent;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        }

        class Program
        {
            public static void Mainq()
            {
                PersonManager personManager = new PersonManager();
                //绑定事件处理方法
                personManager.Myevent += GetNameEv;
                personManager.Execute(new CustomEventArgs("a","b","c"));    //加了event不能直接在外部调用,只能在内部调用

                personManager.delegate1 += GetName;
                personManager.delegate1 += GetOld;
                personManager.delegate1("ssss");     //没加event可在外部直接调用

            }

            public static void GetNameEv(object sender, CustomEventArgs e)
            {

            }

            public static void GetName(string name)
            {
                MessageBox.Show("My name is " + name);
            }
            public static void GetOld(string age)
            {
                MessageBox.Show("My age is " + age);
            }
        }

Tips:
委托和事件的异步执行(多线程的一种)

       class A
        {
            public delegate void de(int a);
            public  de d;
            //public event de d;

        }
        void fun()
        {
            A a = new A();
            //a.d =new A.de(add);
            a.d =add;
            a.d(1);

            //异步执行,可注册完成后的回调事件
            //IAsyncResult asyncResult = a.d.BeginInvoke(2, null, null);


        }
        void add(int i)
        {

        }

https://www.cnblogs.com/wilber2013/p/4285033.html

3.EventHandler

        class CustomEventArgs:EventArgs
        {
            public string From { get; }
            public string To { get; }
            public string Content { get; set; }

            public CustomEventArgs(string from, string to, string content)
            {
                From = from;
                To = to;
                Content = content;
            }

        }

        class MailManager
        {
            //EventHandler<CustomEventArgs>是一个泛型委托,相当于说内部自动写了一个委托,也可以自己写委托实现,见上面PersonManager不带泛型的
            //public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
            public event EventHandler<CustomEventArgs> newMail;

            public void ReceiveNewMail(string from, string to, string content)
            {
                //DoSomething…………
                //触发事件
                CustomEventArgs e = new CustomEventArgs(from, to, content);
                OnNewMail(e);
            }

            //使用虚方法,让子类可以重写
            protected virtual void OnNewMail(CustomEventArgs e)
            {
                //newMail?.Invoke(this,e);

                // 定义一个局部变量,已防止最后一个订阅者刚好在检查null后取消订阅
                EventHandler<CustomEventArgs> handler = newMail;
                if (handler != null)
                {
                    // 格式化事件消息中 的字符串
                    e.Content += String.Format(" at {0}", DateTime.Now.ToString());
                    handler(this, e);
                }


            }

        }

        class MailReader
        {
            public MailReader(MailManager mm)
            {
                //注册事件
                mm.newMail += ReadMail;
            }
            // 实现回调函数。 在事件发生后,执行什么样的操作
            private void ReadMail(object sender, CustomEventArgs e)
            {
                Console.WriteLine(string.Format("fax receive,from:{0} to:{1} content is:{2}", e.From, e.To, e.Content));
            }
        }


        class Class1
        {
            static void Main(string[] args)
            {
                MailManager pub = new MailManager();
                MailReader sub1 = new MailReader(pub);
                MailReader sub2 = new MailReader(pub);
                // 调用这个方法来产生事件
                pub.ReceiveNewMail("a","b","c");

            }
        }

https://www.cnblogs.com/zhaoshujie/p/11042292.html

        //这里定义了一个水箱类
        public class 水箱
        {
            //这是水箱的放水操作
            public void 放水() { }
            //这是水箱的属性
            public double 体积;
            //这是水箱空的事件
            public event EventHandler 水箱空;
        }
        //这里定义了一个加水器类
        public class 加水器
        {
            public void 加水(Object sender, EventArgs e)
            {
                //对需要加水的水箱进行加水操作
            }
        }
        public class User
        {
            public User()
            {
                //实例化水箱类
                水箱1 = new 水箱();
                //实例化加水器类
                加水器1 = new 加水器();
                //加水器注册水箱空事件
                水箱1.水箱空 += new EventHandler(加水器1.加水);
            }
            private 加水器 加水器1;
            private 水箱 水箱1;
        }

EventHandler、EventHandler和delegate对比

        delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
        public event EventHandler<CustomEventArgs> newMail;


        delegate void MyEvent(object sender, CustomEventArgs e);
        public event MyEvent Myevent;


        public event EventHandler 水箱空;

EventHandler跟Action
http://www.paulrohde.com/events-eventhandler-or-action/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值