为什么将事件分配包装在异步匿名函数中?

时间:2018-11-18 20:38:39

标签: c# xamarin xamarin.forms xamarin.ios xamarin.android

在匿名异步函数中包装事件分配是否有意义?

让我们说这段代码在某些适配器类中:

beta

下面的代码在其他设置操作的类中:

示例1:

public event Action<int> someAction;

在这种情况下,HandleAction具有异步Task返回类型。

示例2:

_someAdapter.someAction += async (someParameter) =>
{
    await HandleAction(someParamter);
};

在这种情况下,HandleAction具有异步void返回类型。

相同的问题也适用于按钮单击事件处理程序等。我已经看到了两者的示例,并且想知道为什么有时会把它包装起来。根据我的测试,似乎没有什么区别。

4 个答案:

答案 0 :(得分:1)

我相信,使用匿名处理程序包装器,您将能够让C#垃圾收集器“解钩”并在即将被销毁的this(在示例1)上销毁该处理程序。 / p>

this之外的事件处理程序(在您的示例中不是这种情况)将受到特别注意,并且包装它是一个不错的选择。

如果this可以生存很长时间,并且您有可能不得不再次you should use another strategy to avoid memory leak挂起该事件,就像讨论的on this question

返回类型差异are related to exception handlingit's ok to use an async void on top-level methods and async event handlers

希望对您有帮助。

答案 1 :(得分:1)

在您的示例中,可能没有明显的区别。这更多地与编码标准和最佳实践有关。通常,如果可以避免,建议您不要创建“异步无效”功能。该功能的目的是允许在无法更改其签名的函数中使用异步代码(例如覆盖)。 “异步无效”功能具有吞咽异常和难以组合的缺点。

例如,如果您想从另一个位置/方法调用HandleAction(通常这是使用命名方法而不是匿名函数的原因),除非它返回Task,否则将无法等待。

此外,如果HandleAction引发了异常,则无法等待它就无法捕获它,因此最好确保它会在内部处理所有异常。

答案 2 :(得分:0)

我无法评论您的适配器处理程序,但是...看到您说“相同的问题适用于...”时,答案可能与按钮单击事件处理程序的答案相同,等等,这是(可以说是UI应用程序中异步的最大好处)-您可以在UI线程之外的处理程序中执行昂贵的异步操作。

例如

_button.Click += async (...) =>
{
    int answer = await ExpensiveHttpResultThatTakes10Seconds();
    _answer.Text = answer.ToString();
};

如果不是 异步,则UI将冻结10秒钟,不响应单击,按键等。

由于它是异步的,因此UI在这10秒钟内保持响应,因为等待是无阻塞,正在处理UI事件甚至其他事件处理程序。

答案 3 :(得分:0)

我不建议使用匿名委托作为事件处理程序。原因是它可能涉及循环引用,因此垃圾收集器将无法释放内存-所谓的内存泄漏。

特别是在Xamarin世界中,托管垃圾收集器通常不知道对象的实际大小,因此开发人员应关注内存并分配其应用程序需求。

通过避免匿名委托,您可以通过删除事件处理程序分配来简化周期。