【问题标题】:"Delegate subtraction has unpredictable result" in ReSharper/C#?ReSharper/C# 中的“委托减法具有不可预测的结果”?
【发布时间】:2012-06-26 03:52:35
【问题描述】:

使用myDelegate -= eventHandler ReSharper(版本6)时出现问题:

委托减法有不可预知的结果

这背后的原因是explained by JetBrains here。这个解释是有道理的,读完之后,我怀疑我对代表的所有使用-

那么

  • 我可以编写一个非自动事件而不让 ReSharper 脾气暴躁吗?
  • 或者,是否有更好和/或“正确”的方法来实现这一点?
  • 或者,我可以忽略 ReSharper 吗?

这里是简化的代码:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

public event MyHandler MyEvent
{
    add
    {
        _myEvent += value;
        DoSomethingElse();
    }
    remove
    {
        _myEvent -= value; // <-- ReSharper warning here
    }
}

【问题讨论】:

标签: c# events delegates resharper compiler-warnings


【解决方案1】:

您不应直接使用委托来进行求和或减法。取而代之的是你的领域

MyHandler _myEvent;

也应该被声明为事件。这将解决问题而不会给您的解决方案带来风险,并且仍然具有使用事件的好处。

event MyHandler _myEvent;

使用委托和或减法是危险的,因为在简单地分配委托时可能会丢失事件(根据声明,开发人员不会直接推断这是一个多播委托,因为它被声明为一个事件)。举个例子,如果这个问题中提到的属性没有被标记为一个事件,下面的代码将把前两个分配丢失,因为有人简单地分配给了委托(这也是有效的!)。

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;

在分配 Method3 时,我完全失去了两个初始订阅。事件使用将避免此问题,同时消除 ReSharper 警告。

【讨论】:

  • 我从没想过这样做,但只要您将底层事件保密,保护事件委托的使用确实是有意义的。然而,当在添加/删除处理程序中必须发生更具体的线程同步时,这不起作用,例如多个事件订阅或需要跟踪的子订阅。但是,无论如何它都会删除警告。
【解决方案2】:

将其设置为 = null 而不是使用 -=

【讨论】:

  • 事件的remove 方法不应该删除所有的处理程序,而应该删除被请求删除的处理程序。
  • 如果他只添加了一个,那么如果他只删除了一个,实际上他已经将它们全部删除了。我并不是说在所有情况下都将它用于这个特定的 reshaper 消息。
  • 但是您知道委托总是删除调用列表中的唯一项目。通过将正确的工作代码变成不正确的损坏代码,这些代码会在某些情况下巧合地工作,但在许多情况下会以不寻常且难以诊断的方式中断,从而使重新生成器消息消失。
  • 我不得不对此表示赞成,因为对于花时间写“潜在”答案的人来说,-17 的惩罚太严厉了。 +1 表示不被动,即使您不正确。
【解决方案3】:

别害怕! ReSharper 警告的第一部分仅适用于删除代表列表。在您的代码中,您总是删除一个委托。第二部分讨论了删除重复代表后代表的顺序。事件并不能保证其订阅者的执行顺序,因此它也不会真正影响您。

由于上述机制可能导致不可预知的结果,ReSharper 在遇到委托减法运算符时会发出警告。

ReSharper 发出此警告是因为多播委托减法可能存在问题,它并不完全谴责该语言功能。幸运的是,这些陷阱存在于边缘案例中,如果您只是检测简单事件,则不太可能遇到它们。没有更好的方法来实现您自己的 add/remove 处理程序,您只需要注意。

我建议将该消息的 ReSharper 警告级别降级为“提示”,这样您就不会对他们的警告不敏感,这通常很有用。

【讨论】:

  • 我认为 R# 将结果称为“不可预测”是不好的。他们非常明确地指定。 “不是用户可能预测的”在任何方面都与“不可预测”不同。 (说 .NET 框架定义了重载也是不准确的——它被烘焙到 C# 编译器中。Delegate 确实 not 重载 +-。)
  • @Jon:我同意。我想每个人都习惯了微软为自己设定的高标准。润色度高到不行,.NET世界里有太多让你“掉进成功的坑”的东西,遇到一个语言特性就是快步走到有坑的旁边你可能会错过它被一些人认为是不和谐的,并需要一个标语写着PIT OF SUCCESS IS THAT WAY ---&gt;
  • @AllonGuralnek:另一方面,您最后一次听说有人因此而遇到问题是什么时候?
  • @Jon:听说有问题?在发布此问题之前,我什至不知道这种行为。
  • 奇怪的是,R# 会警告委托减法,但不会警告具有完全相同问题的事件的常见实现。核心问题是 .net 使用单个 Delegate.Combine 来“扁平化”多播委托,因此如果给定委托 [X,Y] 和 Z,它无法判断结果是否应该是 [X,Y,Z]或 [[X,Y],Z](后一个委托持有 [X,Y] 委托作为其 Target,并且该委托的 Invoke 方法作为其 Method)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-22
  • 2021-12-22
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
相关资源
最近更新 更多