In C#, are event handler arguments contravariant?

白昼怎懂夜的黑 提交于 2020-01-15 09:14:24

问题


If I have a class that raises an event, with (e.g.) FrobbingEventArgs, am I allowed to handle it with a method that takes EventArgs?

Here's some code:

class Program
{
   static void Main(string[] args)
   {
      Frobber frobber = new Frobber();
      frobber.Frobbing += FrobberOnFrobbing;
      frobber.Frob();
   }

   private static void FrobberOnFrobbing(object sender,
       EventArgs e)
   {
      // Do something interesting. Note that the parameter is 'EventArgs'.
   }
}

internal class Frobber
{
   public event EventHandler<FrobbingEventArgs> Frobbing;
   public event EventHandler<FrobbedEventArgs> Frobbed;

   public void Frob()
   {
      OnFrobbing();

      // Frob.

      OnFrobbed();
   }

   private void OnFrobbing()
   {
      var handler = Frobbing;
      if (handler != null)
         handler(this, new FrobbingEventArgs());
   }

   private void OnFrobbed()
   {
      var handler = Frobbed;
      if (handler != null)
         handler(this, new FrobbedEventArgs());
   }
}

internal class FrobbedEventArgs : EventArgs { }
internal class FrobbingEventArgs : EventArgs { }

The reason I ask is that ReSharper seems to have a problem with (what looks like) the equivalent in XAML, and I'm wondering if it's a bug in ReSharper, or a mistake in my understanding of C#.


回答1:


Maybe covariant's not the word

Close. The word you are looking for is contravariant. Conversion of a method group to a delegate type is covariant in return type and contravariant in formal parameter types.

Here's my blog article on the subject:

http://blogs.msdn.com/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

if I have a class that raises an event, with (e.g.) FrobbingEventArgs, am I allowed to handle it with a method that takes EventArgs?

Well, you tried it and it worked, so clearly yes. For the justification in the specification see the section helpfully entitled "Method group conversions".




回答2:


Yes you can but when you access the e parameter in the event handler you will only be able to access the members that belong to EventArgs base class unless you cast it as the derived type. I think the word is polymorphic rather than covariant and all classes in c# are pollymorphic, it is a language feature.




回答3:


Since events can only be invoked from within the class that declared them, your derived class cannot directly invoke events declared within the base class.

You can achieve what you want by creating a protected invoking method for the event. By calling this invoking method, your derived class can invoke the event.

For even more flexibility, the invoking method is often declared as virtual, which allows the derived class to override it. This allows the derived class to intercept the events that the base class is invoking, possibly doing its own processing of them.

You can do:

protected void OnFrobbing(EventArgs e) 
   { 
      var handler = Frobbing; 
      if (handler != null) 
         handler(this, new e); 
   } 

Or:

protected virtual void OnFrobbing(EventArgs e) 
   { 
      var handler = Frobbing; 
      if (handler != null) 
         handler(this, new e); 
   } 


来源:https://stackoverflow.com/questions/2833493/in-c-are-event-handler-arguments-contravariant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!