C# 如何注销';匿名';事件处理程序

C# 如何注销';匿名';事件处理程序,c#,.net,events,delegates,anonymous-methods,C#,.net,Events,Delegates,Anonymous Methods,如果我在听一个事件: Subject.NewEvent += delegate(object sender, NewEventArgs e) { //some code }); 现在如何取消注册此事件?还是只允许内存泄漏?是否需要出于泄漏以外的原因取消注册它 关于“或只允许内存泄漏”位,当垃圾收集器清理主题时,您的匿名委托也应该清理,因此不应该有泄漏。如果需要注销事件,我建议避免事件处理程序的匿名委托 在这种情况下,将其分配给本地方法会更好—您可以完全取消订阅事件。为您的匿名委托实例

如果我在听一个事件:

Subject.NewEvent += delegate(object sender, NewEventArgs e)
{
    //some code
}); 

现在如何取消注册此事件?还是只允许内存泄漏?

是否需要出于泄漏以外的原因取消注册它


关于“或只允许内存泄漏”位,当垃圾收集器清理主题时,您的匿名委托也应该清理,因此不应该有泄漏。

如果需要注销事件,我建议避免事件处理程序的匿名委托


在这种情况下,将其分配给本地方法会更好—您可以完全取消订阅事件。

为您的匿名委托实例指定一个名称:

EventHandler<NewEventArg> handler = delegate(object sender, NewEventArgs e)
{
    //some code
};

Subject.NewEvent += handler;
Subject.NewEvent -= handler;
EventHandler=delegate(对象发送方,NewEventArgs e)
{
//一些代码
};
Subject.NewEvent+=处理程序;
Subject.NewEvent-=处理程序;

您可以创建从事件的所有侦听器注销的方法。这并不完全是你想要的,但有时它会很有帮助。例如(这确实有效=):


您需要匿名函数的名称,然后,您只能在该名称在范围内的情况下执行此操作:

    var handler = new EventHandler(delegate(object o, EventArgs e)
    {
        //do something...
    };

    Subject.NewEvent += handler;

    // later on while handler is still in scope...

    Subject.NewEvent -= handler;

要在第一次调用时删除处理程序,请执行以下操作:

//SubjectType Subject = ..... already defined if using (2)

EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
    // (1)
    (sender as SubjectType).NewEvent -= handler;
    // or
    // (2) Subject.NewEvent -= handler;

    // do stuff here
};

Subject.NewEvent += handler;
还有一个问题(我的问题)在某些(太多)细节上进行了探讨:



<>但是,现在已经出来了,我会认真考虑在这种情况下。

内存泄漏是一个原因,另一个原因可能是,我只是想停止听事件,然后你必须存储它,因为DTB的答案暗示,幸运的是,这可能导致泄漏。只要“Subject”仍然是根目录,“this”就永远不会被收集,因为Subject.NewEvent后面的委托将保留对“this”的强烈引用,直到Subject被拔出。WeakEvent模式的存在正是因为这个原因。@Reed:Ah,那么如果在匿名委托中使用“this”,那么它会创建一个循环引用(对象委托),阻止垃圾收集器清理?这就是你的意思吗?不,GC很好地处理循环引用。但是,如果Subject从未被GC'ed(可能是“大型机”在整个应用程序中都存在),那么匿名委托和委托中隐含的“this”都不会被GC'ed。但是,我有一个疑问。谢谢。我不同意-如果你需要创建一个闭包,那么你必须使用一个匿名方法。@free-dom:总是有避免创建闭包的选项(最坏的情况下,你可以做编译器为你做的事情)。在大多数情况下,您计划取消订阅事件的事件处理程序对于您希望关闭的事件来说不是很好的候选。您应该使用易于跟踪的类级状态信息,而不是让编译器为您创建闭包。在这种情况下,闭包往往会导致奇怪的、难以跟踪的问题,并且不具有可维护性。闭包允许您更干净、简洁地传递状态。创建小类并在其上设置状态是非常粗糙的,因此很难维护。关于闭包与方法的争论,我更喜欢闭包。主要原因是,除非必要,否则我不想向类中添加字段(读:两个或更多方法需要共享变量)。使用附加类型保存捕获的值更好,但由于编译器使用闭包时正是这样做的,所以我宁愿使用闭包。为什么这比使用非匿名方法更好?这是非常非常不明显的。@PK:我想这是你能得到的最接近的了。您不能注销无法引用的内容。@里德:匿名委托还有创建闭包的额外好处,这是非匿名方法无法做到的。如果OP希望能够包含无法传递到eventargs的范围内值,那么这是最好的方法。代码示例很可能不起作用,事件很可能永远不会触发。取消订阅必须在处理程序内部进行。我刚刚在这里发布了一个类似的问题:这可能意味着您需要将委托创建为私有成员,如果您在类的另一个部分中执行取消订阅,那么使用方法没有多大好处不知道为什么会被否决--当然,最好首先不要使用持久匿名方法,但是,如果您处于只需要清理它们的情况下,这会非常有效。只需设置
someClass.SomeEvent=null
而不是迭代思想调用列表更容易。使用这种代码,Resharper会抱怨访问修改过的闭包。。。这种方法可靠吗?我的意思是,我们确定匿名方法主体中的'foo'变量真的引用了匿名方法本身吗?我想我自己得到了答案:Resharper是对的,一旦匿名方法被分配给它,捕获的变量('上面例子中的handler')就会改变。因此,它确实发生了变化,但这种机制确保“handler”变量存储对匿名方法itslef的引用。我必须这样做,以便处理程序能够从事件的引发者捕获状态(例如调用方法的参数和局部变量)和状态,这一切都是因为在调用方法退出之前,raiser没有以任何其他方式提供一些所需的信息。这是一个曲折的过程,但它是有效的,不需要创建一个人工类来处理事件。这正是我所需要的。谢谢。看这里
//SubjectType Subject = ..... already defined if using (2)

EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
    // (1)
    (sender as SubjectType).NewEvent -= handler;
    // or
    // (2) Subject.NewEvent -= handler;

    // do stuff here
};

Subject.NewEvent += handler;