multiple options for event handler [duplicate] - c#

This question already has answers here:
Is there a benefit to explicit use of "new EventHandler" declaration?
(4 answers)
Closed 9 years ago.
I am using c# Win Forms with Resharper and it gives me three options for event handler:
eg:
1.button.Click+= (sender, args) => ;
2.button.Click+= delegate(object sender, EventArgs args) { };
3.button3.Click+= Button3OnClick;
private void Button3OnClick(object sender, EventArgs eventArgs)
{
}
So my questions are:
What are the differences between using one over the others?
Is there a preferred way I should stick with?
Thanks

As everyone will tell you, they are equivalent.
One important thing to note though
from How to: Subscribe to and Unsubscribe from Events (C# Programming Guide)
It is important to notice that you cannot easily unsubscribe from an
event if you used an anonymous function to subscribe to it. To
unsubscribe in this scenario, it is necessary to go back to the code
where you subscribe to the event, store the anonymous method in a
delegate variable, and then add the delegate to the event. In general,
we recommend that you do not use anonymous functions to subscribe to
events if you will have to unsubscribe from the event at some later
point in your code.

3) button3.Click += Button3OnClick;
Here you attach delegate which referes to named method Button3OnClick.
2) button.Click += delegate(object sender, EventArgs args) { };
Here you declare anonymous method in .NET 1.1 style. And attach delegate which referes to this anonymous method. Compiler will generate ordinal named method for this anonymous method, so acutally that is same as
button.Click += CompilerGeneratedName;
Where
private void CompilerGeneratedName(object sender, EventArgs args)
{
}
On .NET version > 3 you unlikely will use this syntax, because it was simplified with lambdas.
1) button.Click += (sender, args) => ;
That is exactly same as previous case, but written in lambda syntax. Compiler will generate named method for this anonymous method.
All these options do same - they create and attach delegate which referers to method with required syntax. The only difference is the name of method - method gets name either before compilation, or during compilation.
Is there a preferred way I should stick with?
Usually lambdas (i.e. anonymous methods) are used for very small methods, which just don't worth creating named method manually. But event handlers often not that simple. So, I personally don't like having part of handlers named, and part of attached in-place, because I like to keep code in consistent way. I also like to see usages of event handler, have ability to unsubscribe handler from event, and handler name in stack. So I stick with named handlers. But you always should use same guidlines as your team does.

I would suggest reading up on events and delegates : Delegates and Events
But what it boils down to is that option 3 was always the defacto standard for creating events in .net 2. Since .net 3 delegates got introduced and made it easier to implement with the short hand, option 1 and option 2.
a delegate as used above specifies a place holder containing a signature and return type, the code inside the delegate describes the interactions.
If your learning about events , use option 3 to get your head around it. If you think you have the hang of delegates use option 2. And when it starts boring you to type out everything use option 1
:)

Related

Subscribing to C# EventHandler events from C++\CLI [duplicate]

I'm updating some old Managed C++ code with lines like this:
instanceOfEventSource->add_OnMyEvent(
new EventSource::MyEventHandlerDelegate(this, MyEventHandlerMethod) );
where
EventSource is the class that publishes events
instanceOfEventSource is an instance of that class
EventSource::MyEventHandlerDelegate is the delegate type for the event
MyEventHandlerMethod is a (non-static) method within the current class (of which "this" is an instance) with the signature matching EventSource::MyEventHandlerDelegate
What is the right syntax for this in C++/CLI?
The syntax is similar to C#'s, in other words, += is overloaded to make this possible:
instanceOfEventSource.MyEvent +=
gcnew EventSource::MyEventHandlerDelegate(this, &MyClass::MyEventHandlerMethod);
Analogously for removal. Unlike C#, however, you may not omit the explicit instantiation of the event handler delegate so this produces quite long-winded code.
I just spent half an hour trying to figure out how to register a static method as callback method for an event. While the OP did not specifically ask for registering static methods, this will be helpful to others facing the same problem. It's actually very simple, in that case the delegate constructor takes just one parameter for the static target method.
Example:
System::EventHandler^ h = gcnew System::EventHandler(&MyClass::MyStaticCallbackMethod);

Anonymous function delegate profit

I have a button event declared like this :
myButton.Click += new EventHandler(ButtonClicked);
private void ButtonClicked(Object s, EventArgs e)
{
this.Close();
}
I can do exactly the same like this :
myButton.Click += (s, e) => this.Close();
I'm sure the advantage of using the second way of doing it is not just aesthetic.
Why and when should I use the second method because now I'm confused? If it's just for the look of it, it doesn't look much cleaner when you have more than one instructions in the body of your anonymous function.
Technically there is no difference. Compiler will generate handler method in second case.
But frankly speaking I almost never use anonymous event handlers. Why? because they do not have names. IDE can't help me to find place where event is handled. Do you remember exact place where you subscribed with anonymous method? Well, you possibly remember that place. But I bet your teammates don't.
Also I don't like mixing styles of event handlers. Visual Studio generates for me button1_Click methods. I don't like having some handlers subscribed this way, and some subscribed in place.
And I like to see event argument type. And yes unsubscribing also matters sometime. And few more points - anonymous methods are useful for very simple logic (like closing form in your case), but them become very messy with something more complex. And I think that putting event handler in place breaks single responsibility of your method. It subscribes to event, does some other stuff, and handles event in same place. I like to separate things in order to make them more readable and maintainable.
The compiler generates a method for this anonymous function (s, e) => this.Close(); either way,
It's up to you where you want to use it, declaring it inside a method will however let you access variables declared in that method.
Well you have essentially implictly applied a delegate to your Click event.
You can't access this event in code anywhere else. The main advantage to this is that you can't call your method any where else in your class, by having a method you are inviting other "Team Members" to access the method in their code or potentially change the modifiers of it to what they think should happen.
Should you want to be able to override a method, then obviously inline anonymous assignments are a dis-advantage.
The usage is more or less dependant on how you want to handle access to the logic.
You can do it even more elegant if you do not need the arguments:
myButton.Click += delegate { this.Close(); };
but there is no profit besides elegant look behind it.
I prefer NOT to use lambda expressions ( => ) if I don't really need them as you can't change the scope code during debugging.
Anonymous Functions can be anonymous methods or lambda expressions. The lamba expression is of the form:
() => //dowork
Anonymous Methods are more verbose and support remains mainly for backwards compatibility. Anonymous Functions do not have a value or type in and of themselves, but it is convertible to a delegate or expression tree. Anonymous functions allow us to create in-line methods which are useful in cases such as setting up an event handler. This in-lining of methods allows developers to write code "in the same place". In other words, the handler is immediately available to the reader at the location where the event is handled.
I strive to in-line methods when the implementation is limited to a few statements and not re-useable (as is often the case in event handlers). Lamba Expressions can also used extensively in the framework's extensions methods Enumerable.Select, Where etc. And in place of Action or Func when using the new parallels library or calling Control.Invoke.
Here is a similiar subject: delegate keyword vs. lambda notation that considers anonymous delegates and lambda expressions. Particurarly, the answer there is: Once it is compiled, there is no difference between them.
The first method is easier to support, to make more complex and to reuse.
Also it is not obvious how to unsubscribe the second method from the event
As long as you don't need the parameters, you can even use:
myButton.Click += delegate { this.Close(); };
which looks even cleaner.
But by using anonymous delegates comes the cost of code reusability, as others have pointed out. Also in the article How to: Subscribe to and Unsubscribe from Events. Microsoft states that:
It is important to notice that you cannot easily unsubscribe from an
event if you used an anonymous function to subscribe to it. To
unsubscribe in this scenario, it is necessary to go back to the code
where you subscribe to the event, store the anonymous method in a
delegate variable, and then add the delegate to the event. In general,
we recommend that you do not use anonymous functions to subscribe to events if you will have to unsubscribe from the event at some later
point in your code.
One of the strong points of the anonymous methods, which also separates them from lambda expressions, is that:
... There is one case in which an anonymous method provides
functionality not found in lambda expressions. Anonymous methods
enable you to omit the parameter list. This means that an anonymous
method can be converted to delegates with a variety of signatures.
This is not possible with lambda expressions.
As a conclusion for the paragraph above we can say that you can either pass no parameters at all, or you should pass in the exact signature of the event handler:
myButton.Click += delegate(object sender, EventArgs e) { this.Close(); };

Difference between wiring events using "new EventHandler<T>" and not using new EventHandler<T>"?

What's the difference between the two?
object.ProgressChanged += new EventHandler<ProgressChangedEventArgs>(object_ProgressChanged)
object.ProgressChanged += object_ProgressChanged;
void installableObject_InstallProgressChanged(object sender, ProgressChangedEventArgs e)
{
EventHandler<ProgressChangedEventArgs> progress = ProgressChanged;
if (installing != null)
installing(this, e);
}
EDIT:
If there are no difference, which is the better choice?
Thanks!
Basically, one is shorter than the other. It's just synctactic sugar.
The "correct" syntax is the first one, as ProgresChanged is an EventHandler event, so for you to assign a actual handler to it, you need to create a new EventHandler object, whose constructor takes as a parameter the name of a method with the required signature.
However, if you just specify the name of the method (second syntax), an instance of the eventHandler class is created implicitly, and that instance is assigned to the ProgressChanged event.
I prefer using the second method because it's shorter, and does not lose any information. There are not much contexts where you could mistake a += methodName construct for something else.
No difference. The same ilcode is generated.
As for which one is better: I use the second options since it's cleaner code = easier to read.
No difference. The second one will be implicitely converted to the first by the compiler.
There is no difference between the two, they are same.
In fact, the latter is just a shortcut and it will be compiled like the former.
Riana

Event and delegate contravariance in .NET 4.0 and C# 4.0

While investigating this question I got curious about how the new covariance/contravariance features in C# 4.0 will affect it.
In Beta 1, C# seems to disagree with the CLR. Back in C# 3.0, if you had:
public event EventHandler<ClickEventArgs> Click;
... and then elsewhere you had:
button.Click += new EventHandler<EventArgs>(button_Click);
... the compiler would barf because they're incompatible delegate types. But in C# 4.0, it compiles fine, because in CLR 4.0 the type parameter is now marked as in, so it is contravariant, and so the compiler assumes the multicast delegate += will work.
Here's my test:
public class ClickEventArgs : EventArgs { }
public class Button
{
public event EventHandler<ClickEventArgs> Click;
public void MouseDown()
{
Click(this, new ClickEventArgs());
}
}
class Program
{
static void Main(string[] args)
{
Button button = new Button();
button.Click += new EventHandler<ClickEventArgs>(button_Click);
button.Click += new EventHandler<EventArgs>(button_Click);
button.MouseDown();
}
static void button_Click(object s, EventArgs e)
{
Console.WriteLine("Button was clicked");
}
}
But although it compiles, it doesn't work at runtime (ArgumentException: Delegates must be of the same type).
It's okay if you only add either one of the two delegate types. But the combination of two different types in a multicast causes the exception when the second one is added.
I guess this is a bug in the CLR in beta 1 (the compiler's behaviour looks hopefully right).
Update for Release Candidate:
The above code no longer compiles. It must be that the contravariance of TEventArgs in the EventHandler<TEventArgs> delegate type has been rolled back, so now that delegate has the same definition as in .NET 3.5.
That is, the beta I looked at must have had:
public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);
Now it's back to:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
But the Action<T> delegate parameter T is still contravariant:
public delegate void Action<in T>(T obj);
The same goes for Func<T>'s T being covariant.
This compromise makes a lot of sense, as long as we assume that the primary use of multicast delegates is in the context of events. I've personally found that I never use multicast delegates except as events.
So I guess C# coding standards can now adopt a new rule: don't form multicast delegates from multiple delegate types related through covariance/contravariance. And if you don't know what that means, just avoid using Action for events to be on the safe side.
Of course, that conclusion has implications for the original question that this one grew from...
Very interesting. You don't need to use events to see this happening, and indeed I find it simpler to use simple delegates.
Consider Func<string> and Func<object>. In C# 4.0 you can implicitly convert a Func<string> to Func<object> because you can always use a string reference as an object reference. However, things go wrong when you try to combine them. Here's a short but complete program demonstrating the problem in two different ways:
using System;
class Program
{
static void Main(string[] args)
{
Func<string> stringFactory = () => "hello";
Func<object> objectFactory = () => new object();
Func<object> multi1 = stringFactory;
multi1 += objectFactory;
Func<object> multi2 = objectFactory;
multi2 += stringFactory;
}
}
This compiles fine, but both of the Combine calls (hidden by the += syntactic sugar) throw exceptions. (Comment out the first one to see the second one.)
This is definitely a problem, although I'm not exactly sure what the solution should be. It's possible that at execution time the delegate code will need to work out the most appropriate type to use based on the delegate types involved. That's a bit nasty. It would be quite nice to have a generic Delegate.Combine call, but you couldn't really express the relevant types in a meaningful way.
One thing that's worth noting is that the covariant conversion is a reference conversion - in the above, multi1 and stringFactory refer to the same object: it's not the same as writing
Func<object> multi1 = new Func<object>(stringFactory);
(At that point, the following line will execute with no exception.) At execution time, the BCL really does have to deal with a Func<string> and a Func<object> being combined; it has no other information to go on.
It's nasty, and I seriously hope it gets fixed in some way. I'll alert Mads and Eric to this question so we can get some more informed commentary.
I just had to fix this in my application. I did the following:
// variant delegate with variant event args
MyEventHandler<<in T>(object sender, IMyEventArgs<T> a)
// class implementing variant interface
class FiresEvents<T> : IFiresEvents<T>
{
// list instead of event
private readonly List<MyEventHandler<T>> happened = new List<MyEventHandler<T>>();
// custom event implementation
public event MyEventHandler<T> Happened
{
add
{
happened.Add(value);
}
remove
{
happened.Remove(value);
}
}
public void Foo()
{
happened.ForEach(x => x.Invoke(this, new MyEventArgs<T>(t));
}
}
I don't know if there are relevant differences to regular multi-cast events. As far as I used it, it works ...
By the way: I never liked the events in C#. I don't understand why there is a language feature, when it doesn't provide any advantages.
Are you getting the ArgumentException from both? If the exception is being thrown by just the new handler, then I would think that it's backward-compatible.
BTW, I think you have your comments mixed up. In C# 3.0 this:
button.Click += new EventHandler<EventArgs>(button_Click); // old
wouldn't have run. That's c#4.0
The following code actually works if you have the delegates normalized to the same type from within upon attaching/detaching! I didn't expect detaching to work but it does. It may not be the most optimized solution but it is clean and simple and it solves a serious problem I've had with my Foundation where co-variance is important for example IObservableList : IObservableListOut. At some point extensions created different delegate types depending on context T where T can be 2 different interfaces per context and therefore the delegates created ended up of different type. It wasn't until today that I actually understood how this issue resulted. Detaching won't work with plain "- value".
private event MyEventHandler<T> happened;
public event MyEventHandler<T> Happened
{
add => this.happened += new MyEventHandler<T>(value);
remove => this.happened -= new MyEventHandler<T>(value);
}

What is Difference in assign an event...the correct method?

Can you tell me what the difference is between these methods of attaching an event handler?
//Method 1
this.button4.Click += new RoutedEventHandler(button4_Click);
//Method 2
this.button4.Click += button4_Click;
...
void button4_Click(object sender, RoutedEventArgs e) { }
As Anton says, there's no difference.
Just as a bit more background, this isn't specific to events. That's just one use of the feature in C# 2.0, which is implicit conversion of method groups to delegates. So you can similarly use it like this:
EventHandler handler = button4_click;
Another change to delegates in C# 2.0 is that they're now variant - this means that (for example) you can use a method declared with the EventHander signature as a MouseEventHandler:
MouseEventHandler handler = button4_click;
Then of course there's anonymous methods, but that's a whole different ballgame :)
No difference whatsoever - the second is just syntactic shugar added in C# 2.0. And in C# 3.0 lambdas are even more concise.
It is indeed syntactic sugar (it compiles to identical CIL)
The benefit to the first approach is that it is explict at the call site what event type you are using.
The benefit to the second is that, should the delegate type change but stay compatible the code will not require changing, if it changes but is incompatible you need only fix the method, not the places it is attached to the event.
As ever this is a balance as to which pro/con is more use to the situation at hand

Categories

Resources