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中设置这些异步处理程序没有任何问题,对吗?
该代码似乎可以正常工作,但是有什么我看不到的东西吗?
#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
评论
仅供参考-在ctor中重新使用匿名异步处理程序:我遇到一种罕见的情况,即对csync第一次运行(或已加载/ JIT?)时,对异步处理程序进行细微更改会导致System.InvalidOperationException运行CompilerServices.AsyncMethodBuilderCore。将代码移至命名方法可以避免该错误。 [Xamarin iOS;不知道Win平台是否会受到影响]。 (好消息是,如果发生这种情况,它总是会发生;它不需要实际运行事件代码-因此它不是“潜伏”的问题。)