【问题标题】:Are EventArg classes needed now that we have generics既然我们有泛型,是否需要 EventArg 类
【发布时间】:2008-11-22 15:36:53
【问题描述】:

使用泛型,是否有理由创建特定的派生 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”类做什么。一般使用“EventArgs”类,如果需要一些特定参数,从“EventArgs”派生并添加所需属性。

标签: c# generics eventargs


【解决方案1】:

您所描述的本质上是tuples,用于特定目的的分组值。它们在functional programming 中是一个有用的构造,并且非常支持这种风格。

缺点是它们的值没有命名,并且需要理解上下文。 EventArgs 就其本质而言,通常在远离其相关上下文的地方被消耗。因此,元组式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 类以表达意图为代价简化了机制的开发。

【讨论】:

  • 您的示例可以使用通用事件参数来实现,以返回您自己的类:public class Division { double Num, double Denom, double Result},然后是 EventHandler> .
  • 对于那些使用更新的 C# 7 及更高版本的用户,您现在可以返回命名元组,例如:(bool Result, string Response, ErrorClass Error)。
【解决方案2】:

查看Matthew Cochran 撰写的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】:

我认为元组样式的 EventArgs 很有用。就像 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;
    }
}

可以如下使用(与event raiser extension一起使用时)

public event EventHandler<TupleEventArgs<string,string,string>> NewEvent;

NewEvent.Raise(this, TupleEventArgs.Create("1", "2", "3"));

【讨论】:

    【解决方案4】:

    正如 TcKs 已经说过的:如果您只需要传递一个值,请使用EventArgs&lt;T&gt;,否则从EventArgs(或EventArgs&lt;T&gt;,任何您想要的)派生。

    【讨论】:

    • 但是如果我有一个通用的实现,我不需要创建特定的类。我可以使用它们。 .
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    相关资源
    最近更新 更多