【问题标题】:Unsubscribing from the event in delegate vs function [duplicate]取消订阅委托与函数中的事件[重复]
【发布时间】:2021-10-06 20:33:52
【问题描述】:

为什么当事件处理程序被定义为函数时,C# 允许取消订阅事件,而当事件处理程序被定义为委托时却不允许?

考虑以下有效的代码:

void SomeFunction()
{
  var eventRaiser = ClassRaisingEvent.GetEventRaiser();

  void handler(object sender, EventArgs ev)
  {
    ProcessData(ev);
    eventRaiser.OnEvent -= handler;
  }

  eventRaiser.OnEvent += handler
  eventRaiser.Process();
}

但这无法在指定的位置编译:

void SomeFunction()
{
  var eventRaiser = ClassRaisingEvent.GetEventRaiser();

  DelegateType handler = (object sender, EventArgs ev) =>
  {
    ProcessData(ev);
    eventRaiser.OnEvent -= handler; // FAILS here with "Use of unassigned local variable 'handler '"
  }

  eventRaiser.OnEvent += handler
  eventRaiser.Process();
}

编辑:这个问题不是如何退订。这就是为什么(在技术意义上)函数名称被捕获在函数的范围内,但委托的不是。

EDIT2:答案here(尤其是答案中的第 2 点)解释了我所看到的行为。

【问题讨论】:

  • jpou 如果问题不是关于取消订阅事件,而是关于Delegate 类型的未分配局部变量,您可能应该提供一个与事件无关的更一般的示例。类似于Action action = () => { action(); };。就目前而言,我无法投票支持重新提出您的问题,因为它看起来与How to remove a lambda event handler 非常相似。

标签: c# events delegates


【解决方案1】:

本地函数是在编译时定义的,就像其他函数一样。但是,handler 变量仅在运行时已知。所以,正如编译器告诉你的那样,你不能在 handler 变量被赋值之前使用它,这意味着在你的委托关闭 } 之后。

要让第二个 sn-p 工作,您可以做的是首先初始化变量:

void SomeFunction()
{
  var eventRaiser = ClassRaisingEvent.GetEventRaiser();

  DelegateType handler = null;
  handler = (object sender, EventArgs ev) =>
  {
    ProcessData(ev);
    eventRaiser.OnEvent -= handler;
  };

  eventRaiser.OnEvent += handler;
  eventRaiser.Process();
}

【讨论】:

  • 您建议的方法也会导致“使用未分配的局部变量”错误。
  • @jpou 除了我之前错过的几个分号(现在已在答案中修复)我没有看到相同的错误 - see here
  • 我的错!用“DelegateType handler;”测试而不是“DelegateType handler = null;”您的建议非常有效。
猜你喜欢
  • 2012-02-06
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 2019-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多