.NET:每次事件激发良好做法时都会创建新的EventArgs吗?

时间:2010-01-29 00:12:42

标签: c# events event-handling eventargs

例如,我有一个基本事件发布方法:

    protected virtual OnSomeEvent(EventArgs e)
    {
        var handler = SomeEvent;
        if (handler != null)
        {
            handler(this, e);
            // handler(this, new EventArgs());// EDIT: Yes it should be
                                           // handler(this, e),
                                           // ignore this one :D
        }
    }

对于覆盖OnSomeEvent并在触发时引发其他事件的派生类:

    protected override OnSomeEvent(EventArgs e)
    {
        base.OnSomeEvent(e);

        if (ExtendedEvent != null)
        {
            OnExtendedEvent(e);
        }
    }

    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       ExtendedEvent(this, new ExtendedEventArgs(someStuff, someOtherStuff));
    }

如果派生继续这样,它将为需要它的每一代派生类创建一个新的派生EventArgs。但是,似乎.NET框架上EventArgs的各种派生不是设计为可变的(没有setter),这阻止了一个对象保留一个EventArgs实例并随之修改它。

因此,每当这样的事件触发时,它将为所有涉及的EventArgs对象重新分配内存。在图形密集的应用程序中,事件可以每秒触发几十次(例如控件上的OnPaint事件),这真的是一个好习惯吗?

我应该对OnExtendedEvent()进行一些更改并使ExtendedEventArgs变为可变,以便可以进行以下操作吗?

    protected ExtendedEventArgs extendedArgs = ExtendedEventArgs.Empty;
    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       extendedArgs.someProperty1 = someStuff;
       extendedArgs.someProperty2 = someOtherStuff;

       ExtendedEvent(this, extendedArgs);
    }

编辑:修复了示例代码,现在应该更清楚了。

3 个答案:

答案 0 :(得分:5)

首先,如果你只是忽略它,为什么要把一个EventArgs参数带到你的射击方法?这是真正的浪费,但资源消耗比你的方法告诉其呼叫者的谎言更少问题。只需传递参数,你的触发方法可能无法获得创建EventArgs对象的相关信息:

protected virtual OnSomeEvent(EventArgs e)
{
    var handler = SomeEvent;
    if (handler != null)
    {
        handler(this, e);
    }
}

所以,现在我们已经做到了,如果您的EventArgs对象没有有意义的信息告诉您的订阅者,只需使用EventArgs.Empty,就是它的用途。您可以为自定义的EventArgs类遵循相同的模式,但老实说,您不必担心任何事情。创建EventArgs对象永远不会成为应用程序的瓶颈,如果是,则存在设计问题。

答案 1 :(得分:3)

每次触发时我都会创建一个新的不可变对象,因为事件参数中有值。

主要原因是如果在处理现有事件时再次触发新事件会发生什么?

这可能发生在多线程应用程序中,但甚至可能发生在单个线程上,如以下示例所示:

使用以下值触发第一个事件:

extendedArgs.someProperty1 = "Fire 1";
extendedArgs.someProperty2 = "Fire 1 Other Stuff";

然后以某种方式第一个事件处理程序执行某些操作会导致使用以下参数再次触发事件:

extendedArgs.someProperty1 = "Fire 2";
extendedArgs.someProperty2 = "Fire 2 Other Stuff";

处理第二个事件的所有事件处理程序,现在我们又回来处理第一个事件的其余事件处理程序。

现在,由于使用了相同的对象,第一个事件的所有事件处理程序现在将具有“Fire 2”作为其someProperty1,因为第二个事件覆盖了值。

正如@nobugz所提到的,不要害怕制造短命的垃圾。

答案 2 :(得分:1)

我对您的OnExtendedEvent代码感到有点困惑 - 您是否有意将此事件重新发送为SomeEvent

当客户端添加事件处理程序时,他们希望在处理事件时能够删除事件处理程序,如下所示:

someObject.SomeEvent += OnSomeEvent;
// ...
private void OnSomeEvent(object sender, EventArgs e)
{
    someObject.SomeEvent -= OnSomeEvent;
}

如果您不遵循标准的调度练习,则此代码会使用您的代码给使用者带来惊喜。