.NET:每次事件触发时创建新的 EventArgs 是一个好的做法吗?

发布于 2024-08-19 17:00:14 字数 1737 浏览 5 评论 0原文

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

    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));
    }

如果派生继续这样进行,它将为每一代派生类都需要它。然而,.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);
    }

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

For example, I have a base event publishing method:

    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
        }
    }

For a derived class that overrides OnSomeEvent and raises an additional event when it fires:

    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));
    }

And if derivation goes on like this, it will create a new derived EventArgs for each generation of derived class that requires it. However it seems various derivations of EventArgs on the .NET framework are not designed to be mutable (no setters), this discourages an object from keeping a single instance of EventArgs and modify it as it goes.

So every time an event like this fires, it will re-allocate memory for all involved EventArgs objects. In a graphic intense application where an event can be triggered dozens of times per second (such as OnPaint event on a control), is this really a good practice?

Should I make some changes to OnExtendedEvent() and make ExtendedEventArgs mutable so the following is possible?

    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);
    }

EDIT: Fixed the example code, should be clearer now.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

〃安静 2024-08-26 17:00:14

首先,如果您只是忽略它,为什么要在您的触发方法中使用 EventArgs 参数呢?这是真正的浪费,但资源消耗比你的方法告诉调用者的谎言问题要小。只要传递参数,您的触发方法可能无论如何都不会具有可访问的相关信息来创建 EventArgs 对象:

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

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

First off, why take an EventArgs argument to your firing method if you are just ignoring it anyway? That is the real waste, but the resource consumption is less problematic than the lie that your method is telling its callers. Just pass the argument on through, your firing method likely will not have relevant info accessible to create the EventArgs object anyway:

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

So, now that we have that straight, if your EventArgs object has no meaningful information to tell your subscribers, just use EventArgs.Empty, that's what it is there for. You could follow the same pattern for your custom EventArgs classes, but honestly, you are worrying about nothing. Creating EventArgs objects will never be a bottleneck in your application, and if it is, you have design problems.

沫雨熙 2024-08-26 17:00:14

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

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

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

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

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

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

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

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

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

正如 @nobugz 提到的,不要害怕创建短暂的垃圾。

I would create a new immutable object each time it is fired, as there are values in the event arguments.

The main reason is the what would happen if a new event is fired again while an existing event is being handled?

This will possibly happen in multi-threaded applications but may even happen on a single thread as shown by the following example:

First event is fired with the following values:

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

Then somehow the first event handler does something causes the event to be fired again with the following arguments:

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

All the event handlers are for the second event are processed, and now we are back to processing the rest of the event handlers for the first event.

Now since the same object is used all the event handlers for the first event will now be have "Fire 2" as their someProperty1, as the second event overwrote the values.

As @nobugz mentioned don't be afraid to create short-lived garbage.

驱逐舰岛风号 2024-08-26 17:00:14

我对您的 OnExtendedEvent 代码有点困惑 - 您是否打算将事件作为 SomeEvent 重新分派?

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

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

如果不遵循标准调度实践,此代码将抛出异常,这会让人们大吃一惊使用你的代码。

I'm a little confused by your OnExtendedEvent code - are you meaning to redispatch the event as a SomeEvent?

When a client adds an event handler, they expect they are able to remove the event handler while handling the event, like this:

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

If you do not follow the standard dispatching practice, this code will throw an Exception very much to the surprise of the person using your code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文