+ = new EventHandler (method) vs + = Method

Possible duplicate:
C #: Difference between '+ = anEvent and' + = new EventHandler (anEvent)

There are two main ways to subscribe to an event:

SomeEvent += new EventHandler<ArgType> (MyHandlerMethod); SomeEvent += MyHandlerMethod; 

What is the difference, and when should I choose one after another?

Edit: if this is the same, then why does VS default to using the long version cluttering up the code? It makes no sense to me.

+58
c # events
May 01 '10 at 12:16
source share
5 answers

Since there seemed to be some debate over my initial answer, I decided to do some tests, including looking at the generated code and monitoring performance.

First of all, here is our test bench, a class with a delegate and another class to use it:

 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++; } } 

The first thing to do is look at the generated 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 } 

So it turns out that yes, they generate an identical IL. At first I was wrong. But this is not the whole story . Maybe I'm leaving the topic, but I think it’s important to include this when it comes to events and delegates:

Creating and comparing different delegates is not cheap.

When I wrote this, I thought that the first syntax was able to distinguish a group of methods as a delegate, but it turns out that this is just a transformation. But this is completely different if you are actually saving the delegate. If we add this to the consumer:

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

You can see that it has different characteristics, in terms of performance, from the other two:

 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; } 

Results are subsequently returned as something similar to:

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

This is almost a 20% difference when using saved delegation or creating a new one.

Now it’s obvious that not every program is going to add and remove that many delegates in such a small amount of time, but if you write library classes β€” classes that can be used in ways you cannot predict β€” then you really want to have this difference in mind if you ever need to add and remove events (and I wrote a lot of code that does it personally).

So the conclusion is that the entry SomeEvent += new EventHandler(NamedMethod) compiles to the same thing as SomeEvent += NamedMethod . But if you plan to remove this event handler later, you really need to save the delegate. Despite the fact that the Delegate class has special code that allows you to remove a different delegate from the one you added, it must do a non-trivial amount of work to remove this.

If you are not going to save the delegate, then it does not matter - the compiler still creates a new delegate.

+33
May 01 '10 at 13:45
source share

There is no difference in terms of programming, they are equivalent to each other. The compiler will pretty much do what you did on the first line, with the second line backstage. Therefore, I always chose the second approach (less code).

Re: Your Edit

Perhaps because they feel better to show developers the right way to do something, not shortcuts. Your hunch is as good as mine :)

+24
May 01 '10 at 12:18
source share

the second form is syntactic sugar introduced in later versions of C #. the first line will work in each version though

+8
May 01 '10 at 12:57
source share

There is no difference. Prior to .NET 2.0, all variable assignments must be of the exact type; compilers then did not do much. To get around, VS 2003 emits a new EventHandler around the function name. This is just my guess. Because..

I tried something now in VS 2008, textBox1.KeyDown += (KeyEventHandler)textBox1_KeyDown , which also work. It puzzles me why they select new EventHandler(checkBox1_CheckStateChanged) , and not (EventHandler)checkBox1_CheckStateChanged . But...

since I no longer have VS 2003 in my box, I cannot fix if the casting approach can also work on VS 2003. But afaict, I tried to remove the new EventHandler by function name when I used VS 2003 (.NET 1.1), counting why it is necessary to create an instance ( new EventHandler ) of a function, delegates are just a pointer to a function under the hood, but this will not work.

It is only with .NET 2.0 and beyond that the C # compiler began to output as much as possible.

This article http://blueonionsoftware.com/blog.aspx?p=aed2ae46-7548-4e5f-83c6-95e00c6f3649 supported my memory new EventHandler before .NET 2.0 compilers, it was forced

[EDIT]

The following article details the events of subscription / non-signing, implying the difference between button1.Click += new EventHandler(button1_Click); and button1.Click += button1_Click; but, unfortunately, I do not see differences in the level of IL: - (

http://blogs.msdn.com/abhinaba/archive/2005/08/26/456437.aspx

+7
May 01 '10 at 12:21
source share

There is no difference, the first of them is more defined in the definition.

+2
May 01 '10 at 12:18
source share



All Articles