Являются ли аргументы обработчика событий в C # противоречивыми? - PullRequest
1 голос
/ 14 мая 2010

Если у меня есть класс, который вызывает событие с (например, FrobbingEventArgs), могу ли я обработать его с помощью метода, который принимает EventArgs?

Вот код:

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 ]

6 голосов
/ 14 мая 2010

Может быть, ковариант это не слово

Закрыть. Слово, которое вы ищете, является контравариантным . Преобразование группы методов в тип делегата ковариантно в типе возвращаемого значения и контравариантно в формальных типах параметров.

Вот моя статья в блоге на эту тему:

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

если у меня есть класс, который вызывает событие, с (например) FrobbingEventArgs, могу ли я обработать его с помощью метода, который принимает EventArgs?

Ну, вы попробовали это, и это сработало, так что ясно, да. Обоснование в спецификации см. В разделе «Преобразование групп методов».

1 голос
/ 14 мая 2010

Да, вы можете, но когда вы получите доступ к параметру e в обработчике событий, вы сможете получить доступ только к членам, которые принадлежат базовому классу EventArgs, если вы не приведете его в качестве производного типа. Я думаю, что это слово скорее полиморфное, чем ковариантное, и все классы в c # поллиморфны, это особенность языка.

0 голосов
/ 14 мая 2010

Поскольку события могут вызываться только из класса, который их объявил, ваш производный класс не может напрямую вызывать события, объявленные в базовом классе.

Вы можете достичь желаемого, создав защищенный метод вызова для события. Вызывая этот вызывающий метод, ваш производный класс может вызвать событие.

Для еще большей гибкости вызывающий метод часто объявляется как виртуальный, что позволяет производному классу переопределять его. Это позволяет производному классу перехватывать события, которые вызывает базовый класс, возможно, выполняя их собственную обработку.

Вы можете сделать:

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