创建自定义事件 - 对象发件人或键入的发件人?

时间:2010-07-10 19:14:16

标签: .net events design-patterns anti-patterns

我搜索了档案,我发现了许多关于发件人是什么以及为什么要使用该模式的问题,但我没有看到任何关于自定义事件和类型的发件人。< / p>

假设我正在创建一个名为Subscription的自定义类,它实现了ISubscription,我有一些名为SubscriptionEventArgs的事件args。如果Subscription有一个名为Changed的事件,那么事件签名的更改有什么错误(ISubscription sender,SubscriptionEventArgs e)?

帮助解决问题的一些代码:

public class SubscriptionEventArgs : EventArgs
{
    // guts of event args go here
}

public interface ISubscription
{
    event Action<ISubscription, SubscriptionEventArgs> Changed;
}

public class Subscription : ISubscription
{
    public event Action<ISubscription, SubscriptionEventArgs> Changed;

    private void OnChanged(SubscriptionEventArgs e)
    {
        if (Changed!= null)
        {
            Changed(this, e);
        }
    }
}

如果你只是鄙视使用动作代替“EventHandler”那么你可以做同样的事情,但使用自定义通用的“EventHandler”。

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e);

public class SubscriptionEventArgs : EventArgs
{
    // guts of event args go here
}

public interface ISubscription
{
    event EventHandler<ISubscription, SubscriptionEventArgs> Changed;
}

public class Subscription : ISubscription
{
    public event EventHandler<ISubscription, SubscriptionEventArgs> Changed;

    private void OnChanged(SubscriptionEventArgs e)
    {
        if (Changed!= null)
        {
            Changed(this, e);
        }
    }
}

回应Hans对样本事件处理程序的请求:

public class SubscriptionCollection
{
    // what is actually holding the subscriptions is not really relevant to the question
    private List<ISubscription> _subscriptions;

    public SubscriptionCollection()
    {
        _subscriptions = new List<ISubscription>();
    }

    public void Add(ISubscription subscription)
    {
        subscription.Changed += new EventHandler<ISubscription, SubscriptionEventArgs>(Subscription_Changed);
        _subscriptions.Add(subscription);
    }

    private void Subscription_Changed(ISubscription sender, SubscriptionEventArgs e)
    {
        // Now when the subscription changed event is being handled by the collection
        // I don't have to look up the subscription in the list by some key and I don't 
        // have to cast sender to the correct type because the event handler was typed
        // correctly from the beginning.
    }
}

在列表中查找订阅可能看起来微不足道,但如果我正在使用非常大的数据集并且新的数据量通过实时流进入应用程序,该怎么办呢?必须停止并从列表中获取引用或执行转换步骤的成本没有意义。他们给了我们2.0中的泛型来解决这个问题,所以我不明白为什么我们也没有得到一个通用的事件处理程序,这让我质疑泛型事件处理程序有什么问题?

1 个答案:

答案 0 :(得分:0)

实际上我很困惑为什么在设计.Net Framework v2时,MS没有像你描述的那样提供EventHandler - TSenderTEventArgs同时通用参数。 (在v1和v1.1中,由于它们没有泛型,我完全理解为什么他们没有制作数千个额外的委托类型来处理所有可能的事件。)如果我没记错,你仍然可以使用通用处理程序听一个更具体的事件:

public event EventHandler<Button, MouseDownEventArgs> MouseDown;

private void ObservingMethod(object sender, EventArgs e) { }

MouseDown += new EventHandler<Button, MouseDownEventArgs>(ObservingMethod);

由于你没有将观察者暴露给观察者,我不知道这可能是一个什么问题;一旦你到达事件处理程序,你只是在阻止需要进行类型检查“以防万一”。我认为这是一个很棒的做法,虽然有点不标准,因为MS决定不加入它。

正如我在上面的评论中所指出的,我更愿意看到以下EventHandler的定义,因此你总是可以使用非常通用的处理程序方法,作为我的代码示例:

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e)
    where TEventArgs : EventArgs;