在C#中,事件处理程序参数是否反对?

时间:2010-05-14 10:44:31

标签: c# events contravariance

如果我有一个引发事件的类,使用(例如)FrobbingEventArgs,我是否可以使用带有EventArgs的方法来处理它?<​​/ p>

以下是一些代码:

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

我问的原因是ReSharper似乎在XAML中遇到(看起来像)等效的问题,我想知道它是否是ReSharper中的错误,或者是我对C#的理解错误。

3 个答案:

答案 0 :(得分:6)

  

也许covariant不是单词

关闭。你要找的是逆变。将方法组转换为委托类型的是返回类型中的协变和形式参数类型中的逆变

这是我关于这个主题的博客文章:

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

  

如果我有一个引发事件的类,使用(例如)FrobbingEventArgs,我是否可以使用带有EventArgs的方法来处理它?<​​/ p>

嗯,你尝试了它并且它有效,所以显然是的。有关规范中的理由,请参阅标题为“方法组转换”的部分。

答案 1 :(得分:1)

是的,您可以但是当您在事件处理程序中访问e参数时,您将只能访问属于EventArgs基类的成员,除非您将其作为派生类型进行转换。我认为这个词是多态的而不是协变的,c#中的所有类都是pollymorphic,它是一种语言特征。

答案 2 :(得分:-1)

由于事件只能从声明它们的类中调用,因此派生类不能直接调用在基类中声明的事件。

您可以通过为事件创建受保护的调用方法来实现您的目的。通过调用此调用方法,派生类可以调用该事件。

为了获得更大的灵活性,调用方法通常被声明为virtual,它允许派生类覆盖它。这允许派生类拦截基类正在调用的事件,可能会自己处理它们。

你可以这样做:

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

或者:

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