C# 在处理方法中删除委托成员时,是否可以使用equals赋值?
我的课堂上有以下代码C# 在处理方法中删除委托成员时,是否可以使用equals赋值?,c#,delegates,operators,variable-assignment,dispose,C#,Delegates,Operators,Variable Assignment,Dispose,我的课堂上有以下代码 public class Receiver : IReceiver { public event EventHandler Received; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) {
public class Receiver : IReceiver
{
public event EventHandler Received;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (Received != null)
{
foreach (EventHandler delegateMember in Received.GetInvocationList())
{
Received -= delegateMember;
}
}
}
}
}
这段代码的工作原理是,当我处理我的类时,连接到接收到的事件的任何事件都将被单独删除
我一直在想,与其说它太冗长,不如说下面的简洁版本是否也会有同样的效果
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Received = null;
}
}
基本上,这取决于Microsoft在实现委托重载时如何创建运算符重载。我知道所有的文档都说使用+=订阅活动,使用-=取消订阅活动。我还看到文档中说,当最后一个订户被删除时,事件将被分配为null。文档没有说明的是,将事件分配为null是否会产生取消订阅所有事件的效果
我想知道这是否可行,是否有任何文档表明可能的简洁代码是正确的行为
更新:
我对c#编译器做了更多的挖掘,发现null赋值只在定义事件的类中有效。+=和-=始终可从类内部和外部使用。这导致我认为使用=null版本是可以接受的。但是,这只是猜测,我还没有看到任何文档明确说明这是受支持的功能。没有理由不在此处将
null
分配给代理
如果您不在定义该事件的类的范围内,则不能只分配null
。对于任何使用该类的人来说,他们应该只关心他们自己的处理程序,他们可以添加或删除这些处理程序。他们无法访问其他人的处理程序
您需要记住代理是不可变的。对事件使用+=
不会改变委托以向该委托添加新方法,它会创建一个新委托,当调用该委托时,将调用两个已添加到一起的委托。使用-=
创建一个委托,该委托调用除第二个操作数之外的第一个操作数的所有调用。因此,反复调用-=
会不断创建越来越多的委托,每个委托调用的内容越来越少,直到最终您到达委托不再调用任何东西的地步。只分配null
相当于只创建一个不做任何事情的委托,然后直接分配它
因此,当您反复调用
-=
时,在开始之前分配给事件的原始代理仍然存在,以及N个中间代理。也就是说,没有一个委托可能被任何根元素引用,因此它们都有资格被收集。如果您只分配null
您仍然有原来存在的同一个孤立委托,您就不再有任何中间委托。@DStanley委托仍将引用这些对象,是的,但委托本身将不再是根委托,或从根委托访问,这样就不会让那些被引用的对象保持活动状态了。在发布问题之前,我确实检查了一下是否安静。最基本的问题是使用=和使用-=。在MSDN中,我能找到的最接近的是在本页底部,它说当取消订阅事件处理程序的最后一个实例时,将分配null。我了解您在这里发布的所有内容,并且我知道代码将以两种方式编译。我想问题的关键部分是。。。是不是-=也在做其他事情,但是=作业没有做?如果是,你怎么能确定?到目前为止,我发现的唯一一个与此接近的引用是在本页的底部,它明确表示要使用-=运算符。它确实说您可以测试null以查看是否有订阅者。它并没有说您可以使用=运算符。@ColinDawson除了创建一个新的委托,将第二个操作数从调用列表中排除,然后将该新委托分配给第一个操作数之外,-=/code>运算符没有做任何事情。因此,创建一个不执行任何操作的新委托(也称为null)并直接分配它是等效的。当然,除非任何一个事件处理程序引用定义事件的对象(并且将超过此接收器),否则没有理由这样做,因为整个接收器应该很快停止在第一个位置扎根,也没有理由将其置空。我理解,问题不是你能不能用代码编写它,但是是否有任何文档支持使用=null?我希望能够简单地使用简洁的代码,因为它看起来非常清晰,但我希望确保在引擎盖下,一切都按照预期工作-与示例中的详细代码相同。我要找的是引证,它说这是一个允许的构造。我不想假设它是有效的。你说的很有道理,我理解你是怎么理解的。@ColinDawson:你似乎有一种误解,认为事件或代表是特殊的——它们不是。事件的支持字段具有委托类型,只要它指向委托对象,该委托的调用列表就会保存对对象的引用,并防止对象被收集。当backbacking字段设置为null
时,它将无法使委托对象或任何下游对象保持活动状态(尽管它们可以从根对象图的其他部分继续访问)@ColinDawson:您是指语言规范中的这句话?在声明事件成员的类中,事件的行为类似于委托类型的字段(前提是该事件不是抽象的且不声明访问器)。该字段存储对代表事件的委托的引用