C# 在ReSharper/C中“代理减法具有不可预测的结果”?

C# 在ReSharper/C中“代理减法具有不可预测的结果”?,c#,events,delegates,resharper,compiler-warnings,C#,Events,Delegates,Resharper,Compiler Warnings,使用myDelegate-=eventHandler ReSharper版本6时出现以下问题: 代理减法的结果不可预测 这背后的理性是。这个解释是有道理的,读过之后,我怀疑我对代理的所有使用 那么, 我可以写一个非自动事件而不让ReSharper暴躁吗? 或者,是否有更好和/或正确的方法来实现这一点? 或者,我可以忽略ReSharper吗? 以下是简化代码: public delegate void MyHandler (object sender); MyHandler _myEvent;

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

代理减法的结果不可预测

这背后的理性是。这个解释是有道理的,读过之后,我怀疑我对代理的所有使用

那么,

我可以写一个非自动事件而不让ReSharper暴躁吗? 或者,是否有更好和/或正确的方法来实现这一点? 或者,我可以忽略ReSharper吗? 以下是简化代码:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

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

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

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

ReSharper之所以发出此警告,是因为多播代理减法可能有缺陷,但它并没有完全谴责这种语言特性。幸运的是,这些陷阱处于边缘状态,如果只是检测简单事件,您不太可能遇到它们。没有更好的方法来实现您自己的添加/删除处理程序,您只需要注意一下


我建议降低ReSharper的警告级别,以便提示消息,这样您就不会对他们的警告不敏感,这些警告通常很有用。

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

您不应该直接使用委托求和或求差。而是你的领域

MyHandler _myEvent;
也应该声明为事件。这将在不影响解决方案的情况下解决问题,并且仍然具有事件使用的好处

event MyHandler _myEvent;
使用委托求和或减法是危险的,因为在根据声明简单地分配委托时可能会丢失事件,开发人员不会像将其声明为事件时那样直接推断这是一个多播委托。举个例子,如果这个问题上提到的属性没有被标记为事件,那么下面的代码会将前两个赋值的大小写为丢失,因为有人只是简单地分配给了代理,这也是有效的

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

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

我认为调用结果不可预测是不好的。它们是非常明确的。用户可能预测的与不可预测的完全不同。说.NET framework定义了重载也是不准确的,因为重载是在C编译器中生成的。代理没有重载+和-。@Jon:我同意。我想每个人都习惯了微软为自己设定的高标准。波兰人的水平如此之高,.NET世界中有如此多的东西让你陷入成功的深渊,遇到一个语言特征,就是在你有可能错过的深坑旁轻快地走一走,有些人认为这是不和谐的,并有理由发出一个牌子,上面写着成功的深坑就在那边-->。@AllonGuralnek:另一方面,你最后一次听说有人因为这个而有问题是什么时候?@Jon:听说有问题吗?在发布这个问题之前,我甚至不知道这种行为。奇怪的是,R会警告代理减法,但不会警告具有完全相同问题的事件的常见实现。核心问题是.net使用单个委托.Combine,这会使多播委托平坦化,因此如果给定委托[X,Y]和Z,它无法判断结果是[X,Y,Z]还是[X,Y,Z],后者将[X,Y]委托作为其目标,事件的remove方法不应删除所有处理程序,而应删除请求删除的处理程序。如果他只添加了一个处理程序,那么如果他只删除了一个,那么实际上他将删除所有处理程序。我并不是说在所有情况下都只为这个特定的resharper消息使用它,但是你不知道委托总是删除调用列表上唯一的项。这是通过将正确的工作代码转换为在某些情况下会同时工作的错误断开代码,从而使重拾器消息消失,但在许多情况下,这将打破不寻常的、难以诊断的方式。我不得不对此投赞成票,因为-17对于那些花时间写一个可能的答案的人来说,惩罚太严厉了+1.即使你不正确,也不要被动。Mono给出了同样的警告。下面是R对这个问题的描述,它只适用于被委派者的列表。我从来没有想过这样做,但只要您保持底层事件的私有性,保护事件委派的使用是有意义的。但是,当有更具体的线程同步时,这就不能很好地工作 必须在添加/删除处理程序中进行的远程化,例如需要跟踪的多个事件订阅或子订阅。但是,在任何情况下,它都会删除警告。