委托与C#中的事件有什么区别?
可能重复:
代表和事件有什么区别?
我在面试中得到的这个问题,我仍然不知道答案应该是什么。
我将不胜感激任何想法!
我几乎完全有一篇文章
简而言之,你可以把一个事件想象成一个属性 – 但不是有get / set操作,而是添加/删除。 被添加/删除的值始终是委托参考。
代表们自己支持下列行动:
- 合并(将多个委托实例链接在一起)
- 删除(再次分裂)
- 调用(同步或asynchronous)
- 查找目标,调用列表等等的各种事情
请注意,委托本身是不可变的,所以合并/删除操作返回一个新的委托实例,而不是修改现有的实例。
到目前为止的其他答案都很好。 这是另一种思考方式。
一个属性和一个领域之间的语义区别是什么? 我的意思不是什么技术上的差异,就像一个属性实际上是一对方法,等等等等等等。 我的意思是,就理解程序的意义而言,有什么不同?
一个属性通常是一个类的公共成员,它代表了被build模事物的一个属性。 也就是说,你想制作一个报纸的模型,所以你做一个类报纸,你给它一个属性出版商。 出版商是报纸的财产,所以出版商是报纸类的财产。
一个字段通常是一个类的实现细节 。 也许发布者属性实际上是作为一个字段来实现的。 但是报纸没有“字段”,所以你不要把出版社场作为报纸类的公众成员; 您将其用作发布者属性的私有实现细节。
活动和代表有点类似。 事件是模型中的事情。 button是一个可以通知你点击的事情,所以Button类有一个“Click”事件。 实际进行通知的委托是事件的实现细节。
基本上,委托只是一个什么是C函数指针(或函数指针列表)的包装。
一个事件是一个更高层次的抽象,它把一个委托的概念和用于订阅和取消订阅一个方法的方法一起包装到这样的委托中。
一个事件是一个“属性”,公开了一个add
和remove
方法(通过+=
和-=
在代码中调用)添加/删除订户到一个委托列表。
我欣然承认,这个答复并没有比较代表和事件之间的差别。 但是,我认为在其他人对事件的回复以及对代表的更详细的解释上,你会看到两者之间的区别。 更具体地说,一旦你对代表有了更清晰的认识,我想你会在代表和事件之间获得概念上的区别。
什么帮助我理解一个代表是什么,把它们看作是一个方法的容器。
为了概念化委托如何成为方法的“容器”,请查看这个使用委托来调用三个不同方法的示例 – 请注意,尽pipe使用相同的委托实例来调用三个不同的方法,委托实例将只包含(或目标)在任何给定的时间。
class Program { delegate void MyDelegate(); static void Main() { //Notice how we use the same delegate instance //to target different methods of the same signature MyDelegate myDelegate = new MyDelegate(MethodA); myDelegate(); //Invoke the method myDelegate = MethodB; myDelegate(); myDelegate = MyClass.MethodZ; myDelegate(); Console.ReadLine(); } static void MethodA() { Console.WriteLine("Method 'A' is doing work."); } static void MethodB() { Console.WriteLine("Method 'B' is doing work."); } class MyClass { public static void MethodZ() { Console.WriteLine("Method 'Z' of MyClass is doing work"); } } }
您会注意到,示例中的委托可以包含/定位与委托具有相同签名的任何方法(返回void并在我们的示例中使用零参数)。 如果你在这里停下来消化这个原则,那么你就很好地了解代表。
就这样说,让我困惑的是我什么时候会在代码中明确地实现代表。 上面的示例程序显式使用了一个委托,但没有实际的理由,因为Main()方法可以直接调用目标方法 – 也就是说,我们可以刚刚完成…
static void Main() { MethodA(); MethodB(); MyClass.MethodZ(); Console.ReadLine(); }
那么什么时候我们会明确实现委托呢? Jon Skeet说, 他帮我解答了这个问题
…你可以认为委托types有点像一个方法的接口。
知道一个委托是一个方法的容器,现在,考虑到委托像一个单一的方法接口,考虑这一点:
假设我们有一个程序,将启动不同types的车辆的引擎 – 汽车,摩托车和飞机。
我们的课程将包括车辆级别 – 每种车型一个级别。 每个车辆类别负责启动自己的引擎。 此外,类似于实现一个接口,每个类将确保其启动自己引擎的方法将具有所有其他类(和Main)同意的指定签名。
所以我们有这样的东西:
class VehicleProgram { //All vehicle classes implement their own engine starter method that has this signature delegate void StartEngine(); static void Main() { //The Main doesn't know the details of starting an engine. //It delegates the responsibility to the concrete vehicle class foreach (StartEngine starter in GetVehicleStarters()) { starter(); //Invoke the method } Console.ReadLine(); } static List<StartEngine> GetVehicleStarters() { //Create a list of delegates that target the engine starter methods List<StartEngine> starters = new List<StartEngine>(); starters.Add(Car.StartCar); starters.Add(Motorcycle.StartMotorcycle); starters.Add(Airplane.StartAirplane); return (starters); } class Car { public static void StartCar() { Console.WriteLine("The car is starting."); } } class Motorcycle { public static void StartMotorcycle() { Console.WriteLine("The motorcycle is starting."); } } class Airplane { public static void StartAirplane() { Console.WriteLine("The airplane is starting."); } } }
由于代表拥有方法,我们能够实现一个devise,其中Main()只是获取代表列表,然后调用该方法。 这个devise与我们如何实现接口非常相似。
详细了解何时使用代表而不是接口
委托类似于C / C ++中的函数指针。 它拥有对方法和对象实例的引用(如果该方法是非静态的)。 代表通常是多播的,即它们持有对几个对象/方法对的引用。
事件是基于代表的通知机制。 它公开公开的唯一方法是一对方法(添加/删除)来订阅或取消订阅通知。 委托types用于定义处理程序方法的签名,而订户列表(通常)作为委托在内部存储。
这是一个非常好的文章。
http://www.akadia.com/services/dotnet_delegates_and_events.html
基本上,事件提供了一个紧密耦合的发布订阅范例,而代表提供了一个更松散耦合的devise。
尽pipe如此,事件更简单,更直接。
代表只不过是一个函数指针,在函数中asynchronous调用的地方,但事件只不过是通知。 例如点击button是一个事件,所以你需要订阅button的点击事件等。