如何从委托中解脱异步函数 [重复]

How to unchain asynchronous functions from delegates [duplicate]

提问人:Youssef Bennour Sahli 提问时间:9/12/2023 最后编辑:Youssef Bennour Sahli 更新时间:9/14/2023 访问量:182

问:

我正在处理一个 Blazor 服务器项目,我有一个存储库服务,我从中执行数据库操作,我有一个使用该服务的 razor 组件 X。

基本上,我想在存储库服务中触发某些操作(如添加、更新、删除)的事件,以通知 razor 组件 X 有新的更改。 下面是存储库服务中的事件声明:

Public event Action? SomethingChanged;

我在每个 crud 操作上都调用该事件。 在组件 X 中,我使用异步方法链接该事件(来自存储库服务),如果我使用以下语法执行它,该方法可以正常工作:

protected override OnInitalized()
{
    RepositoryService.SomethingChanged += async () => await AnAsynchronousMethod();
}

我的问题是我无法从事件中取消该异步方法的链接,因为据我所知,以下代码:

public void Dispose()
{
    RepositoryService.SomethingChanged -= async () => await AnAsynchronousMethod();
}

将无法解开异步方法的链接(因为匿名方法将尝试在后台创建另一个方法)。

也许您会发现使用事件来接收更新通知是不合理的,但原因是我这样做是因为我正在将该存储库服务注入另一个组件 Y 中。 在组件 Y 中使用存储库服务所做的更改需要在实际组件 X 中生效。

有没有办法克服这个问题,或者有没有其他你认为更有效的方法。

C# 事件 委托 blazor-server-side

评论


答:

2赞 Jon Skeet 9/12/2023 #1

只需创建一个方法,以便您可以使用方法组转换而不是 lambda 表达式。假设事件是用委托类型(如此同步)声明的,你需要这样的东西:Action

protected override OnInitalized() =>
    RepositoryService.SomethingChanged += InitializationHandler;

public void Dispose() =>
    RepositoryService.SomethingChanged -= InitializationHandler;

// Note: async void is normally an antipattern, but it's common
// for event handlers.
private async void InitializationHandler() =>
    await AnAsynchronousMethod();

评论

0赞 Youssef Bennour Sahli 9/12/2023
谢谢,这工作正常,但是“异步无效”方法签名会导致一些问题,例如丢失堆栈跟踪。如果是这样,你认为我应该关注这一点吗,你是否推荐任何其他方法来解决我上面描述的问题,一种更优雅的方法。
2赞 Jon Skeet 9/12/2023
@YoussefBennourSahli:你认为这会导致 lambda 表达式没有引起的问题吗?lambda 表达式基本上在做同样的事情......这只是从同步方法调用异步方法的产物。
1赞 ℍ ℍ 9/12/2023 #2

这要简单得多:

protected override void OnInitalized()
{
    RepositoryService.SomethingChanged += AnAsynchronousMethod;  // no ()
}

public void Dispose()
{
    RepositoryService.SomethingChanged -= AnAsynchronousMethod;
}

您不想在订阅时调用该方法,因此类似于 。async/await 也可以省略。()address-of

AnAsynchronousMethod()可以(应该)是 .您的代码建议它返回一个 Task,但在引发事件时不可能(可靠)等待它。async void


我正在使用操作类型的事件

那么你确实必须包装它。

async void UpdateHandler() // for += and -=
{
  await InvokeAsync(AnAsynchronousMethod);
  await InvokeAsync(StateHasChanged);
} 

评论

0赞 Youssef Bennour Sahli 9/12/2023
抱歉,我没有提到我正在使用 Action 类型的事件,因此它不以这种方式接受它。
0赞 Youssef Bennour Sahli 9/12/2023
它确实适用于异步无效任务,但是如果我要直接链接“异步任务”,那是不可能的,因为我使用的是 Aciton,在这种情况下,我应该切换到具有返回类型的委托类型。