&引用;代理减法的结果不可预测”;在ReSharper/C#中?

&引用;代理减法的结果不可预测”;在ReSharper/C#中?,c#,events,delegates,resharper,compiler-warnings,C#,Events,Delegates,Resharper,Compiler Warnings,使用myDelegate-=eventHandlerReSharper(版本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
    }
}
公共委托无效MyHandler(对象发送方);
MyHandler myEvent;
公共事件MyEvent
{
添加
{
_myEvent+=值;
DoSomethingElse();
}
去除
{

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

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

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

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

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

您不应该直接使用委托进行求和或减法。而是使用您的字段

MyHandler _myEvent;
也应声明为事件。这将解决问题,而不会危及解决方案,并且仍然具有事件使用的好处

event MyHandler _myEvent;
使用委托求和或减法是危险的,因为在简单地分配委托时,您可能会丢失事件(根据声明,开发人员不会像声明为事件时那样直接推断这是一个多播委托)。仅举个例子,如果此问题中提到的属性未标记为事件,则以下代码将显示前两个分配丢失的情况,因为有人只是将其分配给代理(这也是有效的!)


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

我认为将结果称为“不可预测”是不好的。它们被非常明确地指定。“不是用户可能预测的”与“不可预测”在任何方面都不是一回事。(说.NET framework定义了重载也是不准确的——它被烘焙到C#编译器中。
Delegate
不会重载
+
-
)@乔恩:我同意。我想每个人都习惯了微软为自己设定的高标准。波兰语的水平是如此之高,在.NET世界里有这么多东西让你“跌入成功的深渊”,遇到一个语言特征,就是在坑边轻快地走一走,你可能会错过它,这被一些人认为是不和谐的,并证明有一个标志说,
成功的坑就是这样-->
@AllonGuralnek:另一方面,你上一次听说有人因此而有问题是什么时候它有什么问题吗?在发布这个问题之前,我甚至不知道这种行为。奇怪的是,R#会对委托减法发出警告,但不会对具有完全相同问题的事件的常见实现发出警告。核心问题是.net使用单个
委托。组合
,它“扁平化”多播委托,因此如果给定委托[X,Y]和Z,它无法判断结果是[X,Y,Z]还是[[X,Y],Z](后一个委托将
[X,Y]
委托作为其
目标
,该委托的
调用
方法作为其
方法
)。事件的
remove
方法不应删除所有处理程序,而应删除请求删除的处理程序。如果他只添加了一个处理程序,那么如果他只删除了一个处理程序,则实际上他将删除所有处理程序。我并不是说在所有情况下都只针对此特定的resharper消息使用它。但您不知道委托总是在删除调用列表上唯一的一项。这是通过将正确的工作代码转换为错误的中断代码来消除resharper消息,在某些情况下,这些代码会碰巧工作,但在许多情况下会以异常和难以诊断的方式中断。我不得不对此进行投票,因为-17对于使用此命令的人来说,惩罚太严厉了是时候写一个“潜在”答案了。+1表示即使你不正确,也不要被动。Mono给出了同样的警告。下面是R#对问题的描述(仅适用于学员列表)我从未想过这样做,但只要您将底层事件保持私有状态,就可以保护事件委托的使用。但是,如果必须在添加/删除处理程序中进行更具体的线程同步,例如需要执行多个事件订阅或子订阅,则这项工作不起作用但无论如何,它都会删除警告。
myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;