Нужны ли классы EventArg теперь, когда у нас есть дженерики

StackOverflow https://stackoverflow.com/questions/311432

  •  10-07-2019
  •  | 
  •  

Вопрос

При использовании дженериков всегда есть причина для создания определенных производных классов 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; }
    }
}
Это было полезно?

Решение

То, что вы описываете, - это по сути кортежи , сгруппированные значения, используемые для определенной цели. Они являются полезной конструкцией в функциональном программировании и очень хорошо поддерживают этот стиль.

Недостатком является то, что их значения не названы, и они требуют понимания контекста. 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;
}

Это было бы намного понятнее, если бы <=> представляло событие:

private void OnDivided(object sender, DividedEventArgs e)
{
    var numerator = e.Numerator;
    var denominator = e.Denominator;
    var result = e.Result;
}

Общие многократно используемые <=> классы облегчают разработку механизма за счет выражения намерений.

Другие советы

Посмотрите на пользовательскую универсальную статью 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;

Как уже было сказано в TcK: используйте EventArgs<T>, если вам нужно передать только одно значение, в противном случае вы получите EventArgs (или <=>, что хотите).

Я думаю, что EventArgs в стиле Tuple полезны. Как и в случае с Tuple, ими можно злоупотреблять, но, похоже, моя лень сильнее моего чувства осторожности. Я реализовал следующее:

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"));
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top