我在接受采访时遇到的这个问题,我仍然不知道答案应该是什么 我很感激任何想法!
答案 0 :(得分:62)
我的article非常完全
简而言之,您可以将事件视为有点像属性 - 但它没有获取/设置操作,而是添加/删除。添加/删除的值始终是委托引用。
代表们自己支持以下行动:
请注意,委托本身是不可变的,因此合并/删除操作会返回一个新的委托实例,而不是修改现有的委托实例。
答案 1 :(得分:49)
到目前为止,其他答案都非常好。这是考虑它的另一种方式。
属性和字段之间的语义区别是什么?我不是说什么是技术差异,就像一个属性实际上是一对方法,等等等等等等。我的意思是,就理解程序的含义而言,有什么区别?
属性通常是类的 public 成员,它表示正在建模的事物的属性。也就是说,你想制作一份报纸模型,这样你就可以制作一份报纸,然后给它一个属性发布者。出版商是报纸的财产,因此出版商是报纸类的财产。
字段通常是类的实现细节。也许Publisher属性实际上是作为字段实现的。但报纸上没有“字段”,因此您不要将发布商字段作为报纸类的公共成员公开;您将它用作Publisher属性的私有实现细节。
事件和代表有点类似。事件是模型中的 。按钮是一个可以在单击时通知您的按钮,因此Button类具有“Click”事件。实际进行通知的代表是事件的实现细节。
答案 2 :(得分:17)
基本上,委托只是C(或函数指针列表)中函数指针的包装。
事件是一个更高级别的抽象,它包含委托的概念以及为这些委托订阅和取消订阅方法的方法。
事件是一种“属性”,它公开add
和remove
方法(通过代码中的+=
和-=
调用)以向代理添加/删除订阅者列表。
答案 3 :(得分:8)
委托类似于C / C ++中的函数指针。它包含对方法和对象实例的引用(如果该方法是非静态的)。代理通常是多播的,即它们包含对几个对象/方法对的引用。
事件是一种基于委托的通知机制。它公开披露的唯一内容是一对方法(添加/删除)来订阅或取消订阅通知。委托类型用于定义处理程序方法的签名,订阅者列表(通常)在内部存储为委托。
答案 4 :(得分:8)
我欣然承认,这个回复并没有比较代表和事件之间的区别。但是,我认为其他人为活动提供的回复以及对代表的更详细解释,您会看到两者之间的差异。 更具体地说,一旦你对代表有了更清楚的了解,我认为你将在代表和事件之间获得概念上的区别。
有什么帮助我理解委托是什么,将它们视为单一方法的容器。
为了概念化委托如何是方法的“容器”,请查看此示例,该示例使用委托来调用三种不同的方法 - 请注意,尽管使用相同的委托实例来调用三种不同的方法,但委托实例只会在任何给定时间包含(或定位)一种方法。
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");
}
}
}
您会注意到示例中的委托可以包含/ target任何与委托具有相同签名的方法(返回void并在我们的示例中使用零参数)。如果你在这里暂停并消化这个原则,你就可以开始理解代表了。
话虽如此,让我对代表感到困惑的是,当我在代码中明确地实现委托时。上面的示例程序明确地使用了委托,但没有实际的理由这样做,因为Main()方法也可以直接调用目标方法 - 即我们刚刚完成...
static void Main()
{
MethodA();
MethodB();
MyClass.MethodZ();
Console.ReadLine();
}
那么什么时候我们明确地实现委托?在he said
时,Jon Skeet帮助我回答了这个问题...您可以将委托类型视为 有点像一个接口 单一方法。
知道委托是方法的容器,现在,考虑到委托就像一个具有单一方法的接口,请考虑这一点:
假设我们有一个程序可以启动不同类型车辆的引擎 - 汽车,摩托车和飞机。
我们的计划将包括车辆类 - 每种车型一类。每个车辆类别负责启动自己的发动机。此外,类似于实现接口,每个类将确保其启动其自己的引擎的方法将具有所有其他类(和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.");
}
}
}
由于委托持有方法,我们能够实现一个设计,其中Main()只获取委托列表然后调用该方法。这种设计与我们实现接口的方式非常相似。
答案 5 :(得分:1)
这是一篇非常好的文章。
http://www.akadia.com/services/dotnet_delegates_and_events.html
基本上,事件提供了紧密耦合的发布订阅范例,而代理提供了更松散耦合的设计。
但事件使用起来更简单,更直接。
答案 6 :(得分:0)
代理只是一个函数指针,在函数中异步调用但是事件只是通知。例如,单击按钮是一个事件,因此您需要订阅按钮的单击事件等。