Нужны ли классы EventArg теперь, когда у нас есть дженерики
С generics, существует ли когда-либо причина для создания определенных производных классов EventArg
Кажется, теперь вы можете просто использовать их "на лету" с общей реализацией.
Должен ли я переместить все мои примеры и удалить классы eventArg (StringEventArgs, MyFooEventArgs и т.д.).
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
m_value = value;
}
private T m_value;
public T Value
{
get { return m_value; }
}
}
Ответы
Ответ 1
То, что вы описываете, в основном tuples, сгруппированные значения, используемые для определенной цели. Они полезны в функциональном программировании и очень хорошо поддерживают этот стиль.
Недостатком является то, что их значения не называются, и они требуют понимания контекста. EventArgs
по самой своей природе часто потребляются далеко от их соответствующего контекста. Поэтому tuple-esque EventArgs
может быть очень запутанным для потребителя.
Скажем, у нас есть событие, указывающее, что какое-то деление завершено, и оно несет числитель, знаменатель и результат:
public event EventHandler<EventArgs<double, double, double>> Divided;
Обработчик событий имеет некоторую двусмысленность:
private void OnDivided(object sender, EventArgs<double, double, double> e)
{
// I have to just "know" this - it is a convention
var numerator = e.Value1;
var denominator = e.Value2;
var result = e.Value3;
}
Это было бы намного яснее с EventArgs
, представляющим событие:
private void OnDivided(object sender, DividedEventArgs e)
{
var numerator = e.Numerator;
var denominator = e.Denominator;
var result = e.Result;
}
Универсальные классы повторного использования EventArgs
облегчают разработку механизма за счет выражения намерения.
Ответ 2
Посмотрите Custom Generic EventArgs, написанную Мэтью Кокран, в этой статье он описывает, как расширить его еще больше с двумя и тремя членами.
Использование общих EventArgs использует их использование и, конечно же, их злоупотребления, поскольку информация о типе теряется в процессе.
public class City {...}
public delegate void FireNuclearMissile(object sender, EventArgs<City> args);
public event FireNuclearMissile FireNuclearMissileEvent;
public delegate void QueryPopulation(object sender, EventArgs<City> args);
public event QueryPopulation QueryPopulationEvent;
В следующем примере он безопасен по типу, но немного больше LOC:
class City {...}
public class FireNuclearMissileEventArgs : EventArgs
{
public FireNuclearMissileEventArgs(City city)
{
this.city = city;
}
private City city;
public City City
{
get { return this.city; }
}
}
public delegate void FireNuclearMissile(object sender, FireNuclearMissileEventArgs args);
public event FireNuclearMissile FireNuclearMissileEvent;
public class QueryPopulationEventArgs : EventArgs
{
public QueryPopulationEventArgs(City city)
{
this.city = city;
}
private City city;
public City City
{
get { return this.city; }
}
}
public delegate void QueryPopulation(object sender, QueryPopulationEventArgs args);
public event QueryPopulation QueryPopulationEvent;
Ответ 3
Как уже говорилось, TcKs: используйте EventArgs<T>
, если вам нужно передать только одно значение, иначе выведите EventArgs
(или EventArgs<T>
, что бы вы ни захотели).
Ответ 4
Я думаю, что EventArgs в стиле Tuple полезны. Как и у Tuple's, их можно использовать неправильно, но, похоже, моя лень сильнее, чем мое чувство осторожности. Я выполнил следующее:
public static class TupleEventArgs
{
static public TupleEventArgs<T1> Create<T1>(T1 item1)
{
return new TupleEventArgs<T1>(item1);
}
static public TupleEventArgs<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
{
return new TupleEventArgs<T1, T2>(item1, item2);
}
static public TupleEventArgs<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
{
return new TupleEventArgs<T1, T2, T3>(item1, item2, item3);
}
}
public class TupleEventArgs<T1> : EventArgs
{
public T1 Item1;
public TupleEventArgs(T1 item1)
{
Item1 = item1;
}
}
public class TupleEventArgs<T1, T2> : EventArgs
{
public T1 Item1;
public T2 Item2;
public TupleEventArgs(T1 item1, T2 item2)
{
Item1 = item1;
Item2 = item2;
}
}
public class TupleEventArgs<T1, T2, T3> : EventArgs
{
public T1 Item1;
public T2 Item2;
public T3 Item3;
public TupleEventArgs(T1 item1, T2 item2, T3 item3)
{
Item1 = item1;
Item2 = item2;
Item3 = item3;
}
}
Может использоваться следующим образом (при использовании с расширением расширения )
public event EventHandler<TupleEventArgs<string,string,string>> NewEvent;
NewEvent.Raise(this, TupleEventArgs.Create("1", "2", "3"));