我有一个MVC WinForms应用程序。我将Dependency Injection和Ninject用作IoC容器。

public class SqlObjectExplorerController : ToolController, ISqlObjectExplorerController
{
    private ISqlObjectExplorerView view = null;
    private SqlServerStructureProvider structureProvider;
    private IProgress<IProgressInfo> progress;

    public SqlObjectExplorerController(ISqlObjectExplorerView view)
    {
        if (view == null)
            throw new ArgumentNullException("view");

        this.view = view;
        InitializeEventHandlers();
        ...
    }

    private void InitializeEventHandlers()
    {
        (view as ToolView).Initialize += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
        view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());
        view.OnAddServerInstanceClicked += new EventHandler(async (s, e) => await AddServerInstanceAsync());
        view.OnNewSqlQueryClicked += new EventHandler<NewSqlQueryRequestEventArgs>((s, e) => OpenNewSqlQueryDocument(e));
        view.OnExpandRequested += new EventHandler<BeforeExpandEventArgs>((s, e) => BuildSubStructureForDatabaseNode(e));
    }

    private async Task RefreshObjectExplorerAsync()
    {
        await InitializeObjectExplorerAsync();
        view.InitializeObjectExplorer(ServerCache);
    }

    ... // Lots more code.


我的问题涉及在设置+= new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());之类的对象中使用异步/等待。我需要在后台线程上执行一些任务,所以我正在使用异步/等待,我的问题是关于我的理解的:


执行async (s, e) => await SomeMethodAsync()时,我只是在设置一个事件相当于private async void SomeMethodAsync(object s, EventArgs e) { ... }的处理程序。在我想承担的即发即弃Task的情况下,我认为哪一个很好?
我认为在控制器的ctor中设置这些异步处理程序没有任何问题,对吗?

该代码似乎可以正常工作,但是有什么我看不到的东西吗?

评论

仅供参考-在ctor中重新使用匿名异步处理程序:我遇到一种罕见的情况,即对csync第一次运行(或已加载/ JIT?)时,对异步处理程序进行细微更改会导致System.InvalidOperationException运行CompilerServices.AsyncMethodBuilderCore。将代码移至命名方法可以避免该错误。 [Xamarin iOS;不知道Win平台是否会受到影响]。 (好消息是,如果发生这种情况,它总是会发生;它不需要实际运行事件代码-因此它不是“潜伏”的问题。)

#1 楼

关于async事件处理程序,要考虑的事情是:


为处理程序引发的异常可能会在UI SynchronizationContext上重新抛出,这通常会使应用程序崩溃。引发事件,处理程序将尚未完成。处理程序的执行可能与代码的执行交错​​在一起,在引发多个处理程序并执行之后,也可以使它们相互交错。没问题。


还:

view.OnRefreshObjectExplorerClicked += new EventHandler(async (s, e) => await RefreshObjectExplorerAsync());


您应该可以将其简化为:

view.OnRefreshObjectExplorerClicked += async (s, e) => await RefreshObjectExplorerAsync();



似乎您从未取消订阅事件处理程序,确定可以吗?

评论


\ $ \ begingroup \ $
您如何退订这样的事件处理程序?它显示警告事件通过匿名委托取消订阅
\ $ \ endgroup \ $
–史蒂芬(Stephan)
18-09-27在21:01

\ $ \ begingroup \ $
@Stephan要么使用常规方法而不是lambda进行预订和退订,要么将代表lambda的委托存储在变量中,然后使用该方法进行预订和退订。
\ $ \ endgroup \ $
– svick
18-09-27在21:47



\ $ \ begingroup \ $
应该取消订阅事件发布者是否是IDisposable吗?我曾经读过该事件引用是一个弱引用,因此在处理发布者时,发布者和处理程序都会被垃圾收集。
\ $ \ endgroup \ $
–哈里
19年8月25日在10:24

\ $ \ begingroup \ $
@Harry在大多数情况下,事件引用并不弱。如果您知道发布者将很快被GC,则可以依赖它而不是取消订阅,尽管这与IDisposable无关。
\ $ \ endgroup \ $
– svick
19年8月25日在17:21