【问题标题】:Event unsubscription via anonymous delegate [duplicate]通过匿名委托取消订阅事件[重复]
【发布时间】:2012-02-06 20:27:14
【问题描述】:

我多次使用 Resharper 5.1 代码分析我从 resharper 那里得到一个评论

“通过匿名委托取消订阅事件”

#Part of Code  

if (((bool)e.NewValue))
{
    listView.PreviewTextInput += (o,args) =>
        listView_PreviewTextInput(o,args,listView);
}
else
{
    listView.PreviewTextInput -= (o, args) => 
        listView_PreviewTextInput(o, args, listView);
}

我该如何纠正或优化这件事

【问题讨论】:

    标签: c# wpf attachedbehaviors


    【解决方案1】:

    您可以将 lamdba 提取到变量中:

    EventHandler func = (sender, e) =>
        listView_PreviewTextInput(sender, e, listView);
    
    if (((bool)e.NewValue))
    {
        listView.PreviewTextInput += func;
    }
    else
    {
        listView.PreviewTextInput -= func;
    }
    

    【讨论】:

    • 谢谢,但EventHandler 应该是具体的吧??因为它给了我一个错误...System.EvenTArgs is not assignable to TextCompositonEventArgs
    • 在这种情况下,listView.PreviewTextInput 不是EventHandler,但可能是EventHandler<TextCompositonEventArgs>,但我无法知道,因为您没有在问题中表明这一点。跨度>
    • 是的..我的错..谢谢新的方式... :)
    【解决方案2】:

    警告! 来自 Steven 的Accepted answer错误,它所做的只是掩盖了 resharper 警告的问题。

    每次执行给定代码时

     EventHandler func = (sender, e) =>
         listView_PreviewTextInput(sender, e, listView);
    

    你会得到一个新的(因为你可能会捕获不同的listView)匿名委托实例保存到func,这个实例还没有订阅任何事件,所以反过来这个代码

    listView.PreviewTextInput -= func;
    

    实际上不会做任何事情,因为您无法取消订阅您未订阅的事件。这将导致令人难以置信的错误,例如事件处理程序“调用两次”、内存泄漏等。

    实际上,Jon Skeet 是这么说的 may work in some cases

    C# 规范明确指出 (IIRC) 如果你有两个 匿名函数(匿名方法或 lambda 表达式)可能 或者可能不会从该代码创建相等的委托。

    例如当编译器不是每次都生成新实例时,你会看到很好的行为。

    但这是不可靠的,并且在入门问题中描述的带有捕获变量listView 的情况下肯定行不通。

    所以我的建议是:

    仅当您永远不必取消订阅时才使用匿名函数作为事件处理程序。

    【讨论】:

    • 那么正确的做法是什么?
    • @Daanvl 将匿名委托转为“普通”方法或本地函数
    猜你喜欢
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2020-11-11
    • 2019-05-22
    • 1970-01-01
    相关资源
    最近更新 更多