这是C#中提升事件的有效模式吗?

这是C#中提升事件的有效模式吗?,第1张

概述更新:为了让读者看到这一点的利益,由于.NET 4,由于自动生成事件的同步发生变化,所以锁是不必要的,所以我现在就用这个​​: public static void Raise<T>(this EventHandler<T> handler, object sender, T e) where T : EventArgs{ if (handler != null) { 更新:为了让读者看到这一点的利益,由于.NET 4,由于自动生成事件的同步发生变化,所以锁是不必要的,所以我现在就用这个​​:
public static voID Raise<T>(this EventHandler<T> handler,object sender,T e) where T : EventArgs{    if (handler != null)    {        handler(sender,e);    }}

并提高它:

SomeEvent.Raise(this,new FooEventArgs());

一直在阅读Jon Skeet的articles on multithreading之一,我试图封装他主张通过扩展方法提出一个事件的方法(具有类似的通用版本):

public static voID Raise(this EventHandler handler,object @lock,EventArgs e){    EventHandler handlercopy;    lock (@lock)    {        handlercopy = handler;    }    if (handlercopy != null)    {        handlercopy(sender,e);    }}

这样可以这样调用:

protected virtual voID OnSomeEvent(EventArgs e){    this.someEvent.Raise(this.eventLock,this,e);}

这样做有什么问题吗?

此外,我有点混淆了锁的必要性在第一位.据了解,代理在文中的示例中被复制,以避免在null检查和委托调用之间改变(并变为null)的可能性.但是,我的印象是这种访问/转让是原子的,所以为什么锁是必需的?

更新:关于马克辛普森在下面的评论,我投了一个考验:

static class Program{    private static Action foo;    private static Action bar;    private static Action test;    static voID Main(string[] args)    {        foo = () => Console.Writeline("Foo");        bar = () => Console.Writeline("bar");        test += foo;        test += bar;        test.test();        Console.ReadKey(true);    }    public static voID Test(this Action action)    {        action();        test -= foo;        Console.Writeline();        action();    }}

输出:

FoobarFoobar

这表明方法(action)的delegate参数不会镜像传入它的参数(test),这是我预料的.我的问题是这会影响我在升级扩展方法的上下文中的锁的有效性吗?

更新:这是我正在使用的代码.它不像我想要的那样优雅,但似乎工作:

public static voID Raise<T>(this object sender,ref EventHandler<T> handler,object eventLock,T e) where T : EventArgs{    EventHandler<T> copy;    lock (eventLock)    {        copy = handler;    }    if (copy != null)    {        copy(sender,e);    }}
解决方法 锁定的目的是在您覆盖默认事件线路时维护线程安全性.道歉,如果其中一些是解释你已经能够从乔恩的文章推断的事情;我只是想确保我完全清楚一切.

如果你这样声明你的活动:

public event EventHandler Click;

然后订阅该事件将自动与一个锁同步(这).您不需要编写任何特殊的锁定代码来调用事件处理程序.完全可以写:

var clickHandler = Click;if (clickHandler != null){    clickHandler(this,e);}

但是,如果您决定覆盖默认事件,即:

public event EventHandler Click{    add { click += value; }    remove { click -= value; }}

现在你有一个问题,因为没有隐式的锁了.你的事件处理程序只是失去了线程安全性.这就是为什么你需要使用锁:

public event EventHandler Click{    add    {        lock (someLock)      // normally generated as lock (this)        {            _click += value;        }    }    remove    {        lock (someLock)        {            _click -= value;        }    }}

就我个人而言,我不打扰这个,但乔恩的理由是健全的.但是,我们确实有一个小问题.如果您正在使用一个专用的EventHandler字段来存储事件,那么您可能会在类的内部部署代码:

protected virtual voID OnClick(EventArgs e){    EventHandler handler = _click;    if (handler != null)    {        handler(this,e);    }}

这是坏的,因为我们正在访问相同的私有存储字段,而不使用该属性使用的相同的锁.

如果该类外部的一些代码:

MyControl.Click += MyClickHandler;

通过公共财产的外部代码正在履行锁定.但是你不是,因为你正在触摸私人领域.

clickHandler = _click的变量赋值部分是原子的,是的,但是在该赋值过程中,_click字段可能处于一个暂时状态,一个外部类被半写.当您同步访问某个字段时,只能同步写访问是不够的,您还必须同步读取访问权限:

protected virtual voID OnClick(EventArgs e){    EventHandler handler;    lock (someLock)    {        handler = _click;    }    if (handler != null)    {        handler(this,e);    }}

UPDATE

事实证明,OP的更新证明了围绕评论的一些对话实际上是正确的.这不是扩展方法本身的一个问题,事实上代理具有值类型语义并在赋值时被复制.即使你把这个从扩展方法中拿出来,只是调用它作为一个静态方法,你会得到相同的行为.

尽管我很确定您不能使用扩展方法,但可以使用静态实用程序方法来解决此限制(或特性,具体取决于您的观点).这是一个静态的方法,将工作:

public static voID RaiseEvent(ref EventHandler handler,object sync,EventArgs e){    EventHandler handlercopy;    lock (sync)    {        handlercopy = handler;    }    if (handlercopy != null)    {        handlercopy(sender,e);    }}

这个版本的工作原理是因为我们实际上并没有传递EventHandler,只是引用它(注意方法签名中的引用).不幸的是,您不能在扩展方法中使用ref,因此它必须保持纯静态方法.

(并且如前所述,您必须确保您传递与您在公共事件中使用的sync参数相同的锁定对象;如果传递任何其他对象,那么整个讨论是无效的.)

总结

以上是内存溢出为你收集整理的这是C#中提升事件的有效模式吗?全部内容,希望文章能够帮你解决这是C#中提升事件的有效模式吗?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1259533.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存