精华内容
下载资源
问答
  • C# 委托与事件的区别
    2021-08-09 21:47:49

    1.什么是委托?
    委托可以把一个方法代入另一个方法,相当于指向函数的指针,换句话说,委托相当于一个函数指针,而事件就相当于保存委托的数组。
    总的来说,委托是一个类,该类内部维护着一个字段,指向一个方法。
    委托的声明:public delegate void DoDelegate();
    通过委托执行方法

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
            public delegate void DoDelegate(string valueStr);
            internal void DoFunction()
            {
                //声明一个委托变量,并把已知方法作为构造函数的参数
                DoDelegate doDelegate = new DoDelegate(Test);
                //通过委托的静态方法Invoke触发委托
                doDelegate?.Invoke("传入委托的值!");
            }
    
            void Test(string valueStr)
            {
                Console.Write($"valueStr={valueStr}");
            }
        }
    }	
    

    1.在CLR运行时,DoDelegate实际上是一个类,该类的构造函数有一个参数类型,这个参数类型就是Test方法,并且提供了一个实例Invoke方法,用来触发委托执行;
    2.委托DoDelegate定义了方法的参数和返回值类型;
    3.通过委托DoDelegate的构造函数,可以将符合的方法赋值给委托;
    4.调用委托的实例方法Invoke执行方法。
    委托执行方法的另外一种方式:委托变量(参数列表)

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
            public delegate void DoDelegate(object sender, EventArgs e);
            internal void DoFunction()
            {
                //声明一个委托变量,并将已知方法作为构造函数的参数
                DoDelegate doDelegate = new DoDelegate(Test);
                object sender = 888;
                EventArgs e = new EventArgs();
                doDelegate(sender, e);
            }
            void Test(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
        }
    }	
    

    1.委托DoDelegate的参数列表和Test方法的参数列表保持一致;
    2.委托DoDelegate中的参数object sender通常表示动作的发起者,EventArgs e表示动作所带的参数。
    实际上,事件就是采用委托变量(参数列表)形式执行方法。
    2.什么是事件?
    事件是基于委托的,为委托提供一个订阅或发布的机制。事件是一种特殊的委托,调用事件和委托是一样的。
    事件可以被看作是委托类型的一个变量,通过事件注册、取消多个委托和方法。
    事件的声明:
    public event 委托类型 事件名称;
    如:public event DoDelegate DoEvent;
    通过事件执行方法

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
           public delegate void DoDelegate(object sender, EventArgs e);
            public event DoDelegate DoEvent;
            internal void DoFunction()
            {
                //声明一个委托变量,并将已知方法作为构造函数的参数
                DoDelegate doDelegate = new DoDelegate(Test);
                object sender = 888;
                EventArgs e = new EventArgs();
                DoEvent += new DoDelegate(doDelegate);
                DoEvent(sender, e);
            }
            void Test(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
    }	
    

    1.声明事件DoEvent,事件的类型是DoDelegate委托;
    2.通过+=为事件注册委托;
    3.通过DoDelegate的构造函数为事件注册委托实例;
    4.采用委托变量(参数列表)形式,然事件执行方法。
    通过+=还可以为事件注册多个委托

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
           public delegate void DoDelegate(object sender, EventArgs e);
            public event DoDelegate DoEvent;
            internal void DoFunction()
            {
                //声明一个委托变量,并将已知方法作为构造函数的参数
                DoDelegate doDelegate = new DoDelegate(Test);
                DoDelegate doDe = new DoDelegate(TestExample);
                object sender = 888;
                EventArgs e = new EventArgs();
                //事件注册多个委托
                DoEvent += new DoDelegate(doDelegate);
                DoEvent += new DoDelegate(doDe);
                DoEvent(sender, e);
            }
            void Test(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
            void TestExample(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
    }	
    

    通过+=为事件注册一个或多个委托实例,实际上还可以为事件直接注册方法。
    事件直接注册方法

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
            public delegate void DoDelagate(object sender, EventArgs e);
            public event DoDelagate DoEvent;
            internal void DoFunction()
            {
                object sender = 888;
                EventArgs e = new EventArgs();
                //为事件注册多个委托
                DoEvent += Test;
                DoEvent += TestExample;
                DoEvent(sender, e);
            }
            void Test(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
            void TestExample(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
    }	
    

    通过EventHandler执行方法
    EventHandler的源码:public delegate void EventHandler(object sender, EventArgs e);
    从源码中可以看出,EventHandler是一个委托。使用EventHandler来执行多个方法。

    namespace ConsoleAppCSharp
    {
    	class Program
        {
            static void Main(string[] args)
            {
                DelegateExample delegateExample = new DelegateExample();
                delegateExample.DoFunction();
            }
        }
        class DelegateExample
        {
            public event EventHandler DoEvent;
            internal void DoFunction()
            {
                object sender = 888;
                EventArgs e = new EventArgs();
                //为事件注册多个委托
                DoEvent += Test;
                DoEvent += TestExample;
                DoEvent(sender, e);
            }
            void Test(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
            void TestExample(object sender, EventArgs e)
            {
                Console.Write($"valueStr={sender}");
            }
    }	
    

    总的来说:
    1.委托是一个类,可以实例化,通过委托的构造函数把方法赋值给委托实例;
    2.触发委托有两种方式:委托实例.Invoke(参数列表)和委托实例(参数列表);
    3.事件可看作是一个委托类型的变量;
    4.+=为事件注册多个委托实例或多个方法;
    5.-=为事件减少多个委托实例或多个方法;
    5.EventHandler是一个委托。
    3.委托与实例的区别
    1.事件只能在方法的外部进行声明,而委托在方法的外部和内部都可以进行声明;
    2.事件只能在类的内部进行触发,不能在类的外部进行触发。而委托在类的内部和外部都可触发;
    3.委托一般用于回调,而事件一般用于外部接口。在观察者模式中,被观察者可在内部声明一个事件作为外部观察者注册的接口。

    更多相关内容
  • 本文中,我将通过两个范例由浅入深地讲述什么是委托、为什么要使用委托事件的由来、.Net Framework中的委托事件委托事件对Observer设计模式的意义,对它们的中间代码也做了讨论
  • C#委托与事件初探

    2020-12-31 09:57:37
    委托给了C#操作函数的灵活性,我们可使用委托像操作变量一样来操作函数,其实这个功能并不是C#的首创,早在C++时代就有函数指针这一说法,而在我看来委托就是C#的函数指针,首先先简要的介绍一下委托的基本知识: ...
  • 委托事件这两个概念是完全配合的。委托可以看成是函数指针,那就是说,它能够引用对象方法,通过传递地址的机制完成。委托是一个类,当你对它实例化时,要提供一个对象方法,将其作为它构造函数的参数。
  • C# 委托与事件 猫鼠问题示例。通过猫叫老鼠跑,来展示委托与事件。即通过传递把一个类的方法传递给另外一个类的事件(+=方式注册),在另外一个类中执行事件。
  • C# 委托与事件

    2014-07-16 21:35:34
    讲诉了 C# 中的委托事件的一个Demo,demo 简单易懂,自己认为还是挺不错的。
  • 【原创】C#委托与事件的传递与封装案例 c#经典案例.pdf
  • 详细讲述了C#委托事件的语法及其使用方法,用程序例子深入浅出的讲述了不同的使用方法和这些使用方法的优劣。
  • C#委托与事件案例.rar

    2020-03-18 15:06:14
    之前开发中需要用到委托与事件,找了半天终于找到了Winform下有用的例子,与大家一起学习,亲测可用。
  • C#委托与事件

    2012-02-09 14:28:48
    C#委托与事件的实例,很简单一目了然~里面还包含一个doc的具体分析,适合初学者
  • C#委托与事件[定义].pdf
  • C#委托与事件.pdf

    2019-11-22 10:59:46
    C#开发过程中,委托事件是其中最重要的东西,如果不会使用,那么你的C#开发就无法真正的明白。 共享一点资料出来,共大家一起学习提高,顺便赚点积分,好下载其他同学的资料。 共勉,共勉。。。 。。。
  • 委托事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托事件。对很多接触C#时间不长的人来说并不容易。它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托事件...
  • 深入浅出讲解C#委托与事件
  • C#委托事件详解

    2021-01-08 09:46:10
    B:C#语言里面委托则是让某个方法来实现需求的功能 C:从数据结构方面来讲委托则是和类一样,是一种自定义类型 D:委托它是对方法一类的抽象,就是一系列具有相同签名和返回类型的方法的地址,也就是说它存储的是...
  • 根据经典的实例,详细而全面的介绍了c#委托与事件,以及他们之间的关系
  • c#委托与事件

    2012-08-17 22:51:30
    委托与事件一直都是c#语言比较难啃的一个部分,但是你看完这个文档就全明白了
  • C#委托与事件.doc

    2015-05-21 11:15:00
    C#委托与事件
  • C#委托与事件详解.

    2013-11-13 22:27:38
    委托是一种在对象里保存方法引用的类型,同时也是一种类型安全的函数指针。
  • Common.cs: 代码如下: using System; using System.Collections.Generic; using System.Text; namespace DelegateAndEvent.App_Code { public class ...//这样做是为了看到委托可以执行多个方法. return “hello ”
  • C# 委托与事件,实例代码,调试通过.人个认为对理解C#委托与事件会有一定的帮助.
  • C#中的委托事件

    千次阅读 2021-11-15 14:04:10
    但是就我的观察来看,大多数文在讲述这方面概念时,都会用烧开水和狗叫主人的例子来讲述事件怎么工作,这样比喻固然生活联系紧密,但看多了难免有一些审美疲劳。 所以今天,我打算结合自己的一些工作经历,再来...

    图片

    写在最前

    我相信全网关于委托和事件的文章和概述,大家应该已经读过很多篇。但是就我的观察来看,大多数文在讲述这方面概念时,都会用烧开水和狗叫主人的例子来讲述事件怎么工作,这样比喻固然与生活联系紧密,但看多了难免有一些审美疲劳。

    所以今天,我打算结合自己的一些工作经历,再来谈谈我个人对委托和事件的理解,希望能带给大家一些不一样的见解。

    图片

    先谈概念

    委托:一种引用类型,表示具有特定参数列表和返回类型的方法的引用。在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联。你可以通过委托实例调用方法。委托用于将方法作为参数传递给其他方法。事件处理程序就是通过委托调用的方法。

    事件:类或对象可以通过事件向其他类或对象通知发生的相关事情。发送(或引发)事件的类称为“发布者”,接收(或处理)事件的类称为“订阅者”。

    以上概述来自MSDN官方文档:

    https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/delegates/

    从概念中我们其实已经可以看出,委托主要是对方法的一种引用,而事件则充当了多个类或者对象进行相互通知的桥梁。

    如果我这么解释你可以明白的话,那么我们今天的主题就已经明朗了,下面我们就用具体的代码实例来讲述。

    图片

    再看例子

    委托

    我们需要先声明一个委托实例,在C#中,显示声明自定义委托采用delegate关键字,声明方式与声明普通方法相同,需要指定访问范围和返回类型,同时包含访问参数。

    同时我们针对委托,声明对应的方法,方法的返回值和参数需要与委托保持一致,若不一致则会在委托传递方法时出现编译错误。

    委托执行内部传递方法的方式是使用Invoke方法,此处需注意,C#中同时提供了BeginInvoke和EndInvoke的方法对,用于异步执行内部的方法

    下面我们一起来看一下示例:

    在此示例中,我们分别定义了一个无参数无返回值的委托和一个包含2个参数并返回int类型的委托,分别用于执行两种对应的方法。在两个委托执行对应的Invoke方法之后,会产生以下的结果:

    图片

    结果和我们预期一致,程序同步顺序地执行了两个委托并打印出相应的结果。但是看到这里也许你会有一个疑问,既然委托执行时的结果与直接调用方法一致,那么我们为什么还需要使用委托来执行方法呢?

    这时我们就要回到最初的定义:委托用于将方法作为参数传递给其他方法

    由于实例化的委托是一个对象,因此可以作为参数传递或分配给一个属性。这允许方法接受委托作为参数并在稍后调用委托。这被称为异步回调,是在长进程完成时通知调用方的常用方法。当以这种方式使用委托时,使用委托的代码不需要知道要使用的实现方法。功能类似于封装接口提供的功能。

    我们一起使用一个比较直观的例子来验证:

    using System;
    
    namespace ConsoleApp1
    {
        class Program
        {
            public delegate void Del(string message);
            
            static void Main(string[] args)
            {
                Del handler = new Del(DelegateMethod);
                MethodWithCallback(1,2,handler);
                Console.Read();
            }
    
            public static void DelegateMethod(string message)
            {
                Console.WriteLine(message);
            }
    
            public static void MethodWithCallback(int param1, int param2, Del callback)
            {
                callback(string.Format("当前的值为:{0}", (param1 + param2)));
            }
        }
    }

    在这段代码中,我们声明了一个无返回值委托Del,用于接收传入的消息,并且该委托指向了一个调用控制台的方法DelegateMethod。而后续我们调用MethodWithCallback方法时,无需调用控制台相关方法,而是直接将Del委托的实例作为参数传入,就实现DelegateMethod方法的调用。这个实例就是我们上述提到的异步回调和委托对方法的引用。

    运行结果如下:

    图片

    此处我使用了JetBrains出品的IDE Rider,因此截图界面会与VS有所不同,喜欢轻量级IDE的同学可以试试这款,有30天的免费试用期,地址:Rider: The Cross-Platform .NET IDE from JetBrains,此处不再过多讲解。

    根据我们上述的实例讲解,大家对委托的作用及使用场景应该有了初步的理解,但是我们仔细想一想,上述的场景似乎少了些什么,为什么我们的委托始终只能指向一个方法进行调用呢?

    这里就要引出我们接下来的概念:多播委托。

    事实上,委托是可以调用多个方法的,这种方式就叫做多播委托,在C#中,我们可以使用+=的运算符,将其他委托附加到当前委托之后,就可以实现多播委托,相关示例如下:

    using System;
    
    namespace ConsoleApp1
    {
        class Program
        {
            public delegate void Del();
            
            static void Main(string[] args)
            {
                Del handler = new Del(DelegateMethod1);
                Del handlerNew = new Del(DelegateMethod2);
                handler += handlerNew;
                handler.Invoke();
                Console.Read();
            }
    
            public static void DelegateMethod1()
            {
                Console.WriteLine("天才第一步!");
            }
    
            public static void DelegateMethod2()
            {
                Console.WriteLine("天才第二步!");
            }
        }
    }

    ​​​​​​​在这个示例中,我们重新编写了一个方法叫DelegateMethod2,同时我们又声明了一个新的委托对象handlerNew指向该方法。接着我们使用+=的方式将handlerNew添加至handler并执行该委托,得到的结果如下:

    图片

    如我们先前所料,多播委托把多个方法依次进行了执行。此时如果某个方法发生异常,则不会调用列表中的后续方法,如果委托具有返回值和/或输出参数,它将返回上次调用方法的返回值和参数。与增加方法相对应,若要删除调用列表的方法,则可以使用-=运算符进行操作。

    关于委托的理解与常用方式,我们就讲解到这里,事实上,多播委托常用于事件处理中,由此可见,事件与委托有着千丝万缕的联系,下面我们就拉开事件的序幕。

    事件

    如前文讲解时所说,事件是一种通知行为,因此要分为事件发布者和事件订阅者。而且在.Net中,事件基于EventHandler委托和EventArgs基类的,因此我们在声明事件时,需要先定义一个委托类型,然后使用event关键字进行事件的定义。

    相关的示例如下:

    using System;
    
    namespace ConsoleApp1
    {
        public class PublishEvent
        {
            public delegate void NoticeHandler(string message);
    
            public event NoticeHandler NoticeEvent;
    
            public void Works()
            {
                //触发事件
                OnNoticed();
            }
    
            protected virtual void OnNoticed()
            {
                if (NoticeEvent != null)
                {
                    //传递事件及参数
                    NoticeEvent("Notice发布的报警信息!");
                }
            }
        }
        
        public class SubscribEvent
        {
            public SubscribEvent(PublishEvent pub)
            {
                //订阅事件
                pub.NoticeEvent += PrintResult;
            }
            
            /// <summary>
            /// 订阅事件后的响应函数
            /// </summary>
            /// <param name="message"></param>
            void PrintResult(string message)
            {
                Console.WriteLine(string.Format("已收到{0}!采取措施!",message));
            }
        }
        
        class Program
        {
            static void Main(string[] args)
            {
                PublishEvent publish = new PublishEvent();
                SubscribEvent subscrib = new SubscribEvent(publish);
                //触发事件
                publish.Works();
                Console.Read();
            }
        }
    }

    ​​​​​​​从事例中我们可以看出,我们分别定义了发布者和订阅者相关的类。

    在发布者中,我们需要声明一个委托NoticeHandler,然后定义一个此类型的事件NoticeEvent。在定义对象之后,我们需要对事件进行执行,因此有了OnNoticed方法,此方法只用于事件本身的执行。那么什么时候才能执行事件呢?于是我们又有了触发该事件的方法Works,当Works方法被调用时,就会触发NoticeEvent事件。

    而在订阅者中,我们需要对NoticeEvent事件进行订阅,因此我们需要发布者的对象PublishEvent,同时需要对它的事件进行订阅。正如我们前文所说,订阅使用+=的方式,与多播委托的使用是一致的,而+=后的对象正是我们需要响应后续处理的方法PrintResult。当事件被触发时,订阅者会接收到该事件,并自动执行响应函数PrintResult。

    执行结果如下图所示:

    图片

    从执行结果中我们可以看出,在事件被触发后,订阅者成功接收到了发布者发布的事件内容,并进行自动响应,而我们在此过程中从未显式调用订阅者的任何方法,这也是事件模型的本质意义:从发布到订阅。

    在微软官方文档中提到,事件是一种特殊的多播委托,只能从声明它的类中进行调用。客户端代码通过提供对应在引发事件时调用的方法的引用来订阅事件。这些方法通过事件访问器添加到委托的调用列表中,这也是我们可以使用+=去订阅事件的原因所在,而取消事件则和多播委托一致,使用-=的方式。

    图片

    最后总结

    本文我们讲解了委托和事件之间的关系,以及它们的使用场景。在我个人的工作经历中,曾经有3年左右的时间从事C/S相关的开发工作,其中包含了大量多线程、委托和事件的使用场景。主要用于在开发WinForm程序时,不同窗体(包含父子窗体)之间进行相互通信,其中都是基于事件的发布和订阅作为实现的。而委托的使用场景则更多,很多C#方法在使用时都会传入一个Action或者Func委托作为参数,而这些参数同时又支持Lambda表达式,这就又引出了匿名函数的概念,由于篇幅所限,此处不再进行讲解,大家可以自行搜索资料进行了解和学习。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 80,437
精华内容 32,174
关键字:

c#委托与事件

c# 订阅