ReSharper/C#中的"委托减法有不可预测的结果"?

120 c# resharper events delegates compiler-warnings

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

委托减法具有不可预测的结果

JetBrains在这里解释了这背后的理性.这个解释很有意义,在阅读之后,我怀疑我-对代表的所有用处.

那么如何,

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

这是简化的代码:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

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

All*_*nek 129

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

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

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

我建议将ReSharper对该消息的警告级别降级为"Hint",这样你就不会对他们的警告不敏感,这通常很有用.

  • 我认为R#称结果"不可预测"是不好的.它们非常明确."不是用户可能预测的"与"不可预测的"不同.(说.NET框架定义了重载也是不准确的 - 它被编入C#编译器.`委托`执行*不*重载`+`和`-`.) (64认同)
  • @Jon:我同意.我想每个人都习惯了微软为自己设定的高标准.抛光的程度和它一样高,在.NET世界中有如此多的东西让你"陷入成功的窘境",遇到一种语言特征,就是在坑旁边只有一条轻快的步行道.你可能会错过它的机会被一些人认为是不和谐的,并保证有一个标语说"成功就是这样 - ". (6认同)
  • @AllonGuralnek:另一方面,你最后一次听说有人因此有问题吗? (5认同)
  • @Jon:听说有问题吗?在发布此问题之前,我甚至没有知道此行为. (5认同)
  • 很奇怪R#会警告委托减法,但不会警告具有完全相同问题*的事件的常见实现.核心问题是.net使用单个`Delegate.Combine`来"展平"多播委托,所以如果给出委托[X,Y]和Z,它就不能判断结果是否应该是[X,Y, Z]或[[X,Y],Z](后者委托将`[X,Y]`委托作为`Target`,委托的`Invoke`方法作为`Method`). (2认同)

小智 23

您不应该直接使用委托进行加总或减法.而是你的领域

MyHandler _myEvent;
Run Code Online (Sandbox Code Playgroud)

应该被声明为事件.这将解决问题,而不会有您的解决方案的风险,仍然有事件使用的好处.

event MyHandler _myEvent;
Run Code Online (Sandbox Code Playgroud)

使用委托sum或subtract是危险的,因为在简单地分配委托时你可能会丢失事件(根据声明,开发人员不会直接推断这是一个Multicast委托,因为它被声明为事件).举个例子,如果这个问题中提到的属性没有被标记为事件,下面的代码将使两个第一个赋值保持为LOST,因为有人只是分配给了委托(这也是有效的!).

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;
Run Code Online (Sandbox Code Playgroud)

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