Mse*_*Ali 2 c# asynchronous async-await eventhandler
允许将通常的事件处理程序从 void 转换为基于任务并等待它,如下所示?
Something.PropertyChanged += async (o, args) => await IsButtonVisible_PropertyChanged(o, args);
Something.PropertyChanged -= async (o, args) => await IsButtonVisible_PropertyChanged(o, args);
private Task IsButtonVisible_PropertyChanged(object sender,PropertyChangedEventArgs e)
{
if (IsSomthingEnabled)
{
return SomeService.ExecuteAsync(...);
}
return Task.CompletedTask;
}
Run Code Online (Sandbox Code Playgroud)
或者像这样做?
Something.PropertyChanged += IsButtonVisible_PropertyChanged;
Something.PropertyChanged -= IsButtonVisible_PropertyChanged;
private void IsButtonVisible_PropertyChanged(object sender,PropertyChangedEventArgs e)
{
if (IsSomthingEnabled)
{
_ = SomeService.ExecuteAsync(...);
}
}
Run Code Online (Sandbox Code Playgroud)
更新: 或者这个,我知道 use Task void 应该被禁止,因为它没有捕获异常,但对于事件处理程序的情况可能没问题,因为事件处理程序不返回。
Something.PropertyChanged += IsButtonVisible_PropertyChanged;
Something.PropertyChanged -= IsButtonVisible_PropertyChanged;
private async void IsButtonVisible_PropertyChanged(object sender,PropertyChangedEventArgs e)
{
if (IsSomthingEnabled)
{
await = SomeService.ExecuteAsync(...);
}
}
Run Code Online (Sandbox Code Playgroud)
异步事件处理程序的语法是:
Something.PropertyChanged += IsButtonVisible_PropertyChanged;
...
private async void IsButtonVisible_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
if (IsSomethingEnabled)
{
await SomeService.ExecuteAsync(...);
}
}
Run Code Online (Sandbox Code Playgroud)
这允许在事件处理程序内等待异步操作,而不会阻塞 UI 线程。但这不能用于等待其他方法中的事件。
等待单个事件
如果您希望其他代码等待事件完成,则需要 TaskCompletionSource。任务和基于事件的异步模式 (EAP)对此进行了解释。
public Task<string> OnPropChangeAsync(Something x)
{
var options=TaskCreationOptions.RunContinuationsAsynchronously;
var tcs = new TaskCompletionSource<string>(options);
x.OnPropertyChanged += onChanged;
return tcs.Task;
void onChanged(object sender,PropertyChangedEventArgs e)
{
tcs.TrySetResult(e.PropertyName);
x.OnPropertyChanged -= onChanged;
}
}
....
async Task MyAsyncMethod()
{
var sth=new Something();
....
var propName=await OnPropertyChangeAsync(sth);
if (propName=="Enabled" && IsSomethingEnabled)
{
await SomeService.ExecuteAsync(...);
}
}
Run Code Online (Sandbox Code Playgroud)
这与示例有两个不同之处:
Something以前一样留在记忆中。TaskCreationOptions.RunContinuationsAsynchronously确保任何延续都将在单独的线程上运行。默认情况下是在设置结果的同一线程上运行它们此方法将仅等待一个事件。循环调用每次都会创建一个新的TCS,这是浪费的。
等待事件流
在 C# 8 中引入IAsyncEnumerable之前,不可能轻松地处理await多个事件。使用Channel,可以创建一个发送通知流的方法:IAsyncEnumerable<T>
public IAsyncEnumerable<string> OnPropChangeAsync(Something x,CancellationToken token)
{
var channel=Channel.CreateUnbounded<string>();
//Finish on cancellation
token.Register(()=>channel.Writer.TryComplete());
x.OnPropertyChanged += onChanged;
return channel.Reader.ReadAllAsync();
async void onChanged(object sender,PropertyChangedEventArgs e)
{
channel.Writer.SendAsync(e.PropertyName);
}
}
....
async Task MyAsyncMethod(CancellationToken token)
{
var sth=new Something();
....
await foreach(var prop in OnPropertyChangeAsync(sth),token)
{
if (propName=="Enabled" && IsSomethingEnabled)
{
await SomeService.ExecuteAsync(...);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,只需要一个事件处理程序。每次发生事件时,名为的属性都会被推送到Channel. Channel.Reader.ReadAllAsync()用于返回IAsyncEnumerable<string>可用于异步循环的 。循环将继续运行,直到CancellationToken收到信号为止,在这种情况下,编写器将进入该Completed状态并且IAsyncEnumerable<T>将终止。
| 归档时间: |
|
| 查看次数: |
7957 次 |
| 最近记录: |