Strongly typed sender eventhandler in C #

One thing that annoys me is that in the default event, Sender has an object type and therefore almost always requires manual rendering before we can use it. Fortunately, since VB now also supports dispersion in delegates, we can update the event signature so that the sender is strongly typed, see the event parameter; “sender as object” or “sender” as “T”,

Unfortunately, this does not work for existing declared events that senders have an object of type.

Now, one solution would be to create a fake EventHandler that internally takes care of the cast for you. I made a quick example:

struct EventHandler<TSender, TEventArgs> where TEventArgs: EventArgs { private readonly Action<TSender, TEventArgs> _delegate; public EventHandler(Action<TSender, TEventArgs> @delegate) { if (@delegate == null) throw new ArgumentNullException("@delegate"); _delegate = @delegate; } public static implicit operator EventHandler<TEventArgs>(EventHandler<TSender, TEventArgs> eventHandler) { return new EventHandler<TEventArgs>(eventHandler.Execute); } private void Execute(object sender, EventArgs e) { TSender typedSender = (TSender)sender; TEventArgs typedEventArgs = (TEventArgs)e; _delegate(typedSender, typedEventArgs); } } 

which can be used as you expected it to be used:

 class Program { event EventHandler<EventArgs> Test; static void Main(string[] args) { new Program().Main(); } void Main() { Test += new EventHandler<Program, EventArgs>(TestEventHandler); Test(this, EventArgs.Empty); } void TestEventHandler(Program sender, EventArgs e) { throw new NotImplementedException(); } } 

Now, if I really want to use this, a lot of work remains. (The structure should behave exactly the same as the original delegate). However, I feel that there is either an already excellent implementation there or no implementation, as there are some basic flaws that I have overlooked.

Who can answer this question? Any other clues?

+6
source share
2 answers

I can't think of any solution that would have less code than

 var original = (OriginalType)sender; 

In addition, if the class is not yours, nothing prevents you from creating your own delegate instead of the EventHandler delegate

 delegate void EventHandler<in TSender, in TArgs>(TSender sender, TArgs args); 

This is contravariant in args and sender

People usually also have a reference to the object for which the event is raised, and therefore they rarely need to pull an item from the sender. Is this possible in your case?

Change Since you mentioned that you are dealing with events that are not written by you, so changing the delegate is out of the question, and you probably have no reference to the object, so you need to resort to the sender in this case. Now in your decision you cannot unsubscribe from the event. If you modify it to support this, you will have to keep a link to this structure, which works more than simple casting. I believe casting is still the cleanest solution.

+2
source

I believe that using methods as event handlers is now a bad OOP . Now that we have anonymous delegates, we just don't need to create methods for handling events. Creating an event handler method that can be called by any other method in a class is very similar to making members of the class public and allowing any class to call anything.

In the past, we had to write this:

 public class Program { public void Main() { var button = new Button(); button.Click += button_Click; } void button_Click(object sender, EventArgs e) { var button = (Button)sender; //Need to cast here } } 

But now we can write this:

 public class Program { public void Main() { var button = new Button(); button.Click += (sender, e) => { //Can use `button` here //Just ignore `sender` }; } } 

Using anonymous delegates allows us to directly use the event sender link without the need for casting.

Cleaner Object Oriented Coding.

-1
source

Source: https://habr.com/ru/post/898949/


All Articles