C#之委托与事件

简介:

委托与事件

 

废话一堆:网上关于委托、事件的文章有很多,一千个哈姆雷特就有一千个莎士比亚,以下内容均是本人个人见解。

1. 委托

1.1 委托的使用

        这一小章来学习一下怎么简单的使用委托,了解一些基本的知识。

        这里先看一下其他所要用到的类的信息

         /// <summary>

         /// 函数用例

         /// </summary>

        public class ManyMethodClass

        {

             public ManyMethodClass() { }

             /// <summary> 

             /// 实例函数

             /// </summary>

             /// <param name="strmes"></param>

             public void InstanceMethod(string strmes)

             {

                   Console.WriteLine("实例函数输出:" + strmes);

             }

            /// <summary>

            /// 静态函数

            /// </summary>

            /// <param name="strmes"></param>

            public static void StaticMethod(string strmes)

            {

               Console.WriteLine("静态函数输出:" + strmes);

            }

        }

  • 定义一个委托类型

            public delegate void DisplayStringDelegate(string strmes); 

  • 实例化委托类型

            //绑定实例函数 第一种定义方式(实例函数)

            DisplayStringDelegate disstrdele_instance = new DisplayStringDelegate(newManyMethodClass().InstanceMethod);

            //绑定静态函数 第二种定义方式(静态函数)

            DisplayStringDelegate disstrdele_static = new DisplayStringDelegate(ManyMethodClass.StaticMethod);

            //绑定委托实例 第三种定义方式(委托实例)

            DisplayStringDelegate disstrdele_delegate = new DisplayStringDelegate(disstrdele_instance);

  • 调用委托实例

            disstrdele_instance.Invoke("Hello Word");

            disstrdele_static("Hello Word");

            disstrdele_delegate("Hello Word");

          (ps:这里不同的调用方式效果都是一样的,在下一节会有讲到)

        最后让我们看一下最终的效果图:

271938030606324.png

1.2 委托的定义

  • 委托类型类型

            /// <summary>

            /// 委托示例类

            /// </summary>

           public class DelegateDemonStration

           {

                 public DelegateDemonStration() { }

                 public delegate void DisplayStringDelegate(string strmes);

           }

           在上面的示例代码中,我们定义了一个委托示例类DelegateDemonStration,在DelegateDemonStration的内部我们定义了上一节中讲到的委托的类型DisplayStringDelegate

           在这里先不谈DisplayStringDelegate它定义签名类型,先来谈谈它到底是什么样的存在。

我们来看一下代码:

            /// <summary>

            /// 委托示例类

            /// </summary>

            public class DelegateDemonStration

           {

                   public DelegateDemonStration() { }

                   public class DisplayStringDelegate : MulticastDelegate

                   {

                          public DisplayStringDelegate(object @object, IntPtr method){}

                          public virtual  IAsyncResult BeginInvoke(string strmes, AsyncCallback callback, object @object);

                          public virtual void EndInvoke(IAsyncResult result);

                          public virtual void Invoke(string strmes);

                    }

           }

           当我们定义好一个委托类型的时候,在运行时C#编译器把【public delegate void DisplayStringDelegate(string strmes);】

           编译为【public class DisplayStringDelegate : MulticastDelegate

        所以,各位客官只要记住 在你定义一个委托类型的时候实际上你是定义了一个类

  • 委托实例函数指针

          先让我们来看一下这一小节所要用到的示例代码(所用到的对象类型还是上一小节的内容):

            DisplayStringDelegate disstrdele = newDisplayStringDelegate(newManyMethodClass().InstanceMethod);

            disstrdele += ManyMethodClass.StaticMethod;//这里是委托类型推断 绑定函数的一种方式 几种方式可以自行百度

            disstrdele += new DisplayStringDelegate(ManyMethodClass.StaticMethod);

 

 

            1.第一步  在我们执行DisplayStringDelegate disstrdele = newDisplayStringDelegate(newManyMethodClass().InstanceMethod);的时候,disstrdele实例是如下图一样:

271952214514634.png

 

           2.第二步 当我们继续执行代码 disstrdele += ManyMethodClass.StaticMethod;的时候,请再来看图:

271952311078784.png

           这是disstrdele多指向了一个函数地址,而它的内部实现并不是外表看起来这样简单的:

271952453573738.png

           这里简要的说一下执行第二步的时候

           L_0012:是将第一步的disstrdele实例压入栈中

           L_0013:将一个空引用压入栈中

           L_0014:加载ManyMethodClass.StaticMethod函数地址

           L_001a:实例化DisplayStringDelegate委托类型,假如它叫A

           L_001f:将disstrdele和A合并

           L_0024:将合并好的值转换成DisplayStringDelegate类型,并且存入L_0013中

           L_0029:将L_0013赋值到disstrdele实例

           (以上纯属个人理解,如有偏差请帮忙纠正,谢谢)

           3.第三步 当我们继续执行代码disstrdele += new DisplayStringDelegate(ManyMethodClass.StaticMethod);的时候,过程和第二步相同:

271953082631968.png

           终上所述,委托实例都会指向一个函数地址,当然喽合并过后新的委托实例宁当别论,所以 委托实例函数指针 或者委托实例函数指针列表

1.3 委托实例的调用

         我们来看调用的代码:

          disstrdele("Hello Word");

         这里的内容是接着上一小节的内容继续讲的,拆分开来讲是为了让大家能看的更清楚。

         看一下示意图吧,

271953293414841.png

 

271954580912621.png

        从这里就可以看出来了,虽然disstrdele 实例是合并后的委托实例,它的屁股上挂上了好多函数地址,但是执行这样函数的入口还只是一个,那就是Delegate.Invoke(string),

        如果有人要问它的Invoke(string)内部是怎么实现的,暂时回答不了,因为具体的代码是动态生成的吧,不过我们可以自己猜想或者想象一下它是怎么实现的。

        在这里就不多说了。

 

       看了以上的内容能大概的知道或者分清一些概念性的东西。

       这里本人只是讲了一把剑是由铁铸成的,可以用来切割、刺、劈、砍,至于这把剑怎么用就因人而异了。

2. 事件

2.1 事件是什么?

       这一章我们来学习一下事件

     照旧我们先来看一下示例代码:

public class EventDomeStration

       {

public EventDomeStration() { }

 /// <summary>

             /// 定义好的一个示例

             /// </summary>

public event DisplayStringDelegate DisplayStringEventHandler;

        }

        在上面的代码中,我们定义了一个事件DisplayStringEventHandler,而在它名称前面的是一个DisplayStringDelegate委托类型(就是我们上一节所说的委托)。

        就对于它而言来看一下MSIL,看看它究竟是什么样的:

        .class public auto ansi beforefieldinit EventDomeStration extends [mscorlib]System.Object

         {

              .field private class DelegateCaseAndEventCase.DisplayStringDelegate DisplayStringEventHandler

              .event DelegateCaseAndEventCase.DisplayStringDelegate DisplayStringEventHandler

              {

                 .addon instance void DelegateCaseAndEventCase.EventDomeStration::add_DisplayStringEventHandler(class DelegateCaseAndEventCase.DisplayStringDelegate) 

                 .removeon instance void DelegateCaseAndEventCase.EventDomeStration::remove_DisplayStringEventHandler(class DelegateCaseAndEventCase.DisplayStringDelegate)

               }

        }

        从这里可以看到,定义好的一个事件就是一个私有(DisplayStringDelegate委托类型)的字段加上一个事件访问器,也就是相当于C#代码的这样:

        public class EventDomeStration

        {

                public EventDomeStration() { }

                private DisplayStringDelegate displaystringdele;

                public event DisplayStringDelegate DisplaystringEventHandler

               {

                     add

                    {

                         displaystringdele += value;

                    }

                    remove

                   {

                        displaystringdele -= value;

                   }

               }

         }

         在这里本人对事件的定义是:

       事件就是所在对象里的属性,而属性的类型是委托类型,它是负责架设与外部对象即时通讯(传递消息)的桥梁,桥梁本身就是委托。

2.2 事件的使用

         出门在外务工,难免要租房子住,每次找房子是件头疼的事请各位客官一起来看一下,就拿这个来举个例子。

         先定义一个委托:publicdelegatevoid消息反馈(string 反馈房子信息);

         首先得有一个中介,暂且叫它为房产中介1, 来看一下它的内部定义:

         public class 房产中介1
         {
              public 房产中介1() { }
              public 房产中介1(string 具体要求)
              {
                   房源信息处理(具体要求);
              }
             public event 消息反馈 消息通知;
             public string 客户要求的信息_1 = string.Empty;
             private void 房源信息处理(string 客户要求的信息)
             {
                  //逻辑处理
                  //假如是有客户需要的 则通知客户
                 if (消息通知 != null)
                 {
                     消息通知("有房子,什么样的,信息等等");
                 }
                 客户要求的信息_1 = 客户要求的信息;
                 //逻辑处理要是没有 把信息移交给了中介2
                 房产中介2 中介2 = new 房产中介2(this);   
              }
              public void 其它中介消息通知(string 房子信息)
              {
                  if (消息通知 != null)
                  {
                      消息通知(房子信息);
                  }
               }
           }

         中介有了,那现在我想要开始租房子怎么办?没关系,找中介。

        首先先把“”定义出来:

         public class 

         {

                 //比如我要租房子

                 public 我(){ }

                 public void  我要租房子(string 具体的要求)

                {

                       //找的是房产中介1

                      房产中介1 中介1 = new 房产中介1(具体的要求);

                      中介1.消息通知 += new 消息反馈(中介1_消息通知);

                 }

                 void 中介1_消息通知(string 房子信息)

                 {

                        //我可以从【房子信息】中知道是否有有合适的房子,如果有得话,是什么样的

                }

          }

          public class 房产中介2

          {

                public string 客户要求信息 = string.Empty;

                public 房产中介2() { }

                public 房产中介2(房产中介1 中介1)

                {

                     房源信息处理(中介1);

                }

                private void 房源信息处理(房产中介1 中介1)

               {

                    //逻辑处理

                    //判断是否有满足 ->中介1.客户要求的信息_1值条件的房源

                    //如果有

                   中介1.其它中介消息通知("房子有的,房子的信息等等");

                }

          }

 

          上面定义了 房产中介1房产中介2,现在 我 要找房子了

          我 me = new ();

           me.我要租房子("有床就行");

          好了,“”已经把信息发布出去了,现在就坐等房产中介1的通知了。

 

          因为事件只能是对象本身内部触发,这个设计是合理,为什么不能用委托,委托也可以实现同样的功能啊?

          假如用了委托,这个例子的意思就是“我”可以控制房产中介1有没有找到房子信息,这个是不符合常理的。

          因为“我”是找的房产中介1房产中介1根据“我”的要求没找到,把这个信息交给了房产中介2,让房产中介2帮忙找找,然后中房产中介2找到了,

          但是中房产中介2并不能直接通知“我”,如果可以直接通知的话,这样“我”会告房产中介1侵犯客户隐私,

          所以只能是房产中介2告诉房产中介1找到了【也就是代码:房产中介1.其它中介消息通知("房子有的,房子的信息等等");】,然后再由房产中介1来通知“我”。

 

相关文章
|
2月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
118 7
|
3月前
|
C#
由浅入深理解C#中的事件
由浅入深理解C#中的事件
109 19
|
3月前
|
编译器 C#
C#中内置的泛型委托Func与Action
C#中内置的泛型委托Func与Action
65 4
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
81 0
|
3月前
|
C#
C#中的委托(一)
C#中的委托(一)
38 1
|
3月前
|
存储 算法 安全
C#语言进阶(二)—事件全解
C#语言进阶(二)—事件全解
37 0
|
3月前
|
C# C++
C#语言进阶(一)—委托
C#语言进阶(一)—委托
50 0
|
6月前
|
存储 安全 C#
C# - 委托与事件
这篇文档介绍了C#中的委托和事件。委托是存储方法引用的类型,支持回调、事件处理,具有引用方法、类型安全、多播性等特性,并在异步编程中发挥作用。事件是委托的封装,提供保护和订阅机制,防止外部直接访问。当需要在类内部控制方法调用,防止外部误触发时,可使用事件。
|
5月前
|
C#
C#||委托和事件的实例
C#||委托和事件的实例
|
6月前
|
C#
c#委托详解
c#委托详解
38 0