提升事件,将调用其事件处理程序。例如http://msdn.microsoft.com/en-us/library/aa645739%28VS.71%29.aspx
使用事件机制和直接调用其他方法有什么区别(例如,如果在方法A()中满足条件,则调用B())?
消费和举起活动有什么区别?
由于
答案 0 :(得分:21)
区别在于:
方法调用 =“执行此特定操作”
事件提升 =“如果有人在倾听和关心,这件事就发生了。”
它是分离关注和可重用性的核心。如果单击它调用特定方法,则按钮不是可重用组件。但如果它只是“宣布”它被点击的程序,并且有兴趣的各方负责订阅它,它是无限可重用的。
如何实现(通过委托)的基础技术实现是无关紧要的。
答案 1 :(得分:6)
举办活动,将召集活动 处理
开始出错了。可能有 no 事件处理程序。或者很多。你不知道。这与直接调用方法的主要区别在于。在你最喜欢的设计模式书中查找“观察者模式”。
答案 2 :(得分:2)
提升活动(或调用,使用链接中的术语)意味着您要将活动发送给所有消费者。例如,窗口可以在用鼠标单击时引发事件。
使用事件意味着您正在接收和处理发送事件的任何人。例如,您可能想知道鼠标单击窗口的时间。
如果您只有一个消费者,那么您可以通过直接提供回调来完成类似的事情:
// 'Event' type:
delegate void DelMyEvent();
// consumer:
class Consumer
{
Producer _theProducer;
void RegisterForNotification()
{
_theProducer.OnMyEvent = new DelMyEvent(OnMyEvent);
}
void OnMyEvent() { }
}
// producer:
class Producer
{
public DelMyEvent OnMyEvent;
void SendNotification()
{
if( OnMyEvent != null ) OnMyEvent();
}
}
事件机制通过阻止使用者直接设置委托值来清除这一点。相反,它使消费者使用+=
运算符注册自己。当第一个使用者注册时,委托被设置,当第二个使用者注册时,他们的两个回调被Delegate.Combine
链接在一起。
答案 3 :(得分:2)
对于对事件调用表现感兴趣的任何人,我都做了这个简单的基准测试。 它显示了直接调用方法,通过接口调用它,通过委托和via事件之间的区别,其中附加了一个处理程序。
在每个场景中,该方法以相应的方式被调用1 000 000 000次。以下是(可能令人惊讶的)结果:
代表电话:23 240毫秒 - 最快的
事件电话:23 295 ms
直接电话:23 396 ms
接口调用:23 716 ms - 最慢的
使用.NET4.0中的C#在发布版本中完成了测量。
代码在这里:
class Program
{
static void Main(string[] args)
{
TestClass.RunTest();
Console.ReadLine();
}
}
interface ITestClass
{
void TestMethod(object sender, TestEventArgs eventErgs);
}
class TestClass : ITestClass
{
#region Events
event EventHandler<TestEventArgs> TestEvent;
#endregion
#region Constructor
public TestClass()
{
TestEvent += TestMethod;
}
#endregion
#region Public Methods
public static void RunTest()
{
int testCount = 1000000000; //1 000 000 000
string format = "{0:### ### ### ##0}";
#region Direct Call
Console.WriteLine("Direct call");
TestClass testClass = new TestClass();
testClass.TestMethod(testClass, new TestEventArgs(3));
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < testCount; ++i)
{
testClass.TestMethod(testClass, new TestEventArgs(3));
}
stopwatch.Stop();
Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds));
Console.WriteLine();
#endregion
#region Interface Call
Console.WriteLine("Interface call");
ITestClass itestClass = new TestClass();
itestClass.TestMethod(testClass, new TestEventArgs(3));
stopwatch = Stopwatch.StartNew();
for (int i = 0; i < testCount; ++i)
{
itestClass.TestMethod(testClass, new TestEventArgs(3));
}
stopwatch.Stop();
Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds));
Console.WriteLine();
#endregion
#region Delegate Call
Console.WriteLine("Delegate call");
TestClass delegateTestClass = new TestClass();
Action<object, TestEventArgs> delegateMethod = delegateTestClass.TestMethod;
delegateMethod(testClass, new TestEventArgs(3));
stopwatch = Stopwatch.StartNew();
for (int i = 0; i < testCount; ++i)
{
delegateMethod(testClass, new TestEventArgs(3));
}
stopwatch.Stop();
Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds));
Console.WriteLine();
#endregion
#region Event Call
Console.WriteLine("Event call");
TestClass eventTestClast = new TestClass();
eventTestClast.TestEvent(testClass, new TestEventArgs(3));
stopwatch = Stopwatch.StartNew();
for (int i = 0; i < testCount; ++i)
{
eventTestClast.TestEvent(testClass, new TestEventArgs(3));
}
stopwatch.Stop();
Console.WriteLine(string.Format(format, stopwatch.ElapsedMilliseconds));
Console.WriteLine();
#endregion
}
#endregion
#region ITestClass Members
public void TestMethod(object sender, TestEventArgs e)
{
e.Result = e.Value * 3;
}
#endregion
}
class TestEventArgs : EventArgs
{
public int Value { get; private set; }
public int Result { get; set; }
public TestEventArgs(int value)
{
Value = value;
}
}
答案 4 :(得分:1)
使用之间有什么区别 事件机制和直接调用 到其他方法(例如,如果条件是 在方法A()中遇到,调用B())?
业务逻辑明智,两者之间没有区别。我的意思是你可以单程完成同样的任务。这只是一种不同的方式。真正的区别在于您处理其他模块通知所需的工作量。
通过举起一个活动,你实际上是在说“嘿,发生了一些代码已经注册,当发生这种情况时会收到通知,让他们知道。哪些模块得到通知并不是我的关注,因为我是假设(在运行时)所有需要知道的模块都设置为通知。“
通过直接调用每个方法,您决定要告诉这个(或这些)模块,只有这些模块已经发生了什么。你正在断言,无论这些模块的状态如何都不重要,他们需要知道这个事件发生了。
两者都适用于不同的情况。事件通知更具动态性。不同的模块可以注册和取消注册通知。直接方法调用更加静态。绝对会通知某些对象(或模块等)(除非当然例外)发生了某些事情,但只会通知这些对象。
答案 5 :(得分:0)
除了上面的多个/无订阅者场景之外,事件还用于减少代码耦合 - 例如,方法A()在编译时不需要知道关于方法B()的任何信息。这样可以更好地分离关注点和不那么脆弱的代码。
在野外,您更有可能看到框架和UI代码中使用的事件,而在应用程序的域逻辑中,开发人员更经常使用Separated Interface和Dependency Injection之类的东西来解耦代码。最近在各种领域进行了一些关于在域逻辑中使用事件的讨论,这种方法被巧妙地命名为Domain Events。