栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

+ =新的EventHandler(Method)与+ =方法[重复]

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

+ =新的EventHandler(Method)与+ =方法[重复]

由于我的原始答案似乎有些争议,因此我决定进行一些测试,包括查看生成的代码 监视性能。

首先,这是我们的测试平台,一个带有委托的类和另一个使用它的类:

class EventProducer{    public void Raise()    {        var handler = EventRaised;        if (handler != null) handler(this, EventArgs.Empty);    }    public event EventHandler EventRaised;}class Counter{    long count = 0;    EventProducer producer = new EventProducer();    public void Count()    {        producer.EventRaised += CountEvent;        producer.Raise();        producer.EventRaised -= CountEvent;    }    public void CountWithNew()    {        producer.EventRaised += new EventHandler(CountEvent);        producer.Raise();        producer.EventRaised -= new EventHandler(CountEvent);    }    private void CountEvent(object sender, EventArgs e)    {        count++;    }}

首先要做的是查看生成的IL:

.method public hidebysig instance void Count() cil managed{    .maxstack 8    L_0000: ldarg.0     L_0001: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_0006: ldarg.0     L_0007: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)    L_000d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)    L_0012: callvirt instance void DelegateTest.Program/EventProducer::add_EventRaised(class [mscorlib]System.EventHandler)    L_0017: ldarg.0     L_0018: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_001d: callvirt instance void DelegateTest.Program/EventProducer::Raise()    L_0022: ldarg.0     L_0023: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_0028: ldarg.0     L_0029: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)    L_002f: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)    L_0034: callvirt instance void DelegateTest.Program/EventProducer::remove_EventRaised(class [mscorlib]System.EventHandler)    L_0039: ret }.method public hidebysig instance void CountWithNew() cil managed{    .maxstack 8    L_0000: ldarg.0     L_0001: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_0006: ldarg.0     L_0007: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)    L_000d: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)    L_0012: callvirt instance void DelegateTest.Program/EventProducer::add_EventRaised(class [mscorlib]System.EventHandler)    L_0017: ldarg.0     L_0018: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_001d: callvirt instance void DelegateTest.Program/EventProducer::Raise()    L_0022: ldarg.0     L_0023: ldfld class DelegateTest.Program/EventProducer DelegateTest.Program/Counter::producer    L_0028: ldarg.0     L_0029: ldftn instance void DelegateTest.Program/Counter::CountEvent(object, class [mscorlib]System.EventArgs)    L_002f: newobj instance void [mscorlib]System.EventHandler::.ctor(object, native int)    L_0034: callvirt instance void DelegateTest.Program/EventProducer::remove_EventRaised(class [mscorlib]System.EventHandler)    L_0039: ret }

事实证明,是的,它们确实产生相同的IL。我本来是错的。但这 还不是全部 。可能是我不在这里讨论话题,但是我认为在讨论事件和委托时将其包括在内很重要:

创建和比较不同的代表并不便宜。

当我写这篇文章时,我以为第一种语法能够将方法组强制转换为委托,但事实证明,这只是一个转换。但是,当您实际 保存
委托时,情况就完全不同了。如果将其添加到使用者:

class Counter{    EventHandler savedEvent;    public Counter()    {        savedEvent = CountEvent;    }    public void CountSaved()    {        producer.EventRaised += savedEvent;        producer.Raise();        producer.EventRaised -= savedEvent;    }}

你可以看到,这有 非常 不同的特性,性能明智的,从其他两个:

static void Main(string[] args){    const int TestIterations = 10000000;    TimeSpan countTime = TestCounter(c => c.Count());    Console.WriteLine("Count: {0}", countTime);    TimeSpan countWithNewTime = TestCounter(c => c.CountWithNew());    Console.WriteLine("CountWithNew: {0}", countWithNewTime);    TimeSpan countSavedTime = TestCounter(c => c.CountSaved());    Console.WriteLine("CountSaved: {0}", countSavedTime);    Console.ReadLine();}static TimeSpan TestCounter(Action<Counter> action, int iterations){    var counter = new Counter();    Stopwatch sw = new Stopwatch();    sw.Start();    for (int i = 0; i < TestIterations; i++)        action(counter);    sw.Stop();    return sw.Elapsed;}

结果始终像以下内容一样返回:

Count: 00:00:02.4742007CountWithNew: 00:00:02.4272702CountSaved: 00:00:01.9810367

使用保存的委托与创建新委托相比,几乎相差 20%

现在显然不是每个程序都会在这么短的时间内添加和删除这么多的委托,但是如果您正在编写库类(可能无法使用的类使用类),那么您真的想保留此类如果您需要添加
和删除 事件(我已经写了很多代码来亲自完成),请记住这些区别。

因此,结论是,写作

SomeEvent += new EventHandler(NamedMethod)
与just编译相同
SomeEvent +=NamedMethod
。但是,如果您打算以后 删除 该事件处理程序,则 确实应该 保存
委托
。即使
Delegate
该类具有一些特殊情况的代码,允许您从添加的代理中删除引用不同的委托,它也必须完成大量工作才能实现这一目标。

如果您不打算保存委托,则没有任何区别-编译器最终还是会创建一个新的委托。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/575931.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号