我有一个视图模型,它是我的Android和iOS应用程序的UDP网络浏览器(由Xamarin推动)。 UDP用于广播应用程序的活动实例并监听广播,以便发现本地(Wifi)网络上的其他应用程序实例。
我的视图模型具有属性
public AppInstanceList AppInstances
{
get; set;
}
还有一种方法
public async Task StartDiscoveringAppInstancesAsync()
设置一个while循环,它继续通过UPD异步监听:
while(this.networkService != null)
{
var discoveredInstance = await this.networkService.DiscoverAppInstanceAsync ();
// Omitted: store the discovered instance and add to list of discovered instances.
this.AppInstances.Add(...);
// Wait a bit before checking again.
await Task.Delay(1000);
}
此方法的问题是Task
的返回类型。显然,不应该等待该方法 - 它是无限循环并且一直运行直到发现停止。
我应该将其更改为void
吗?但这会违反async / await原则,其中void
只应用于事件。
每当我遇到类似这样的话题时,我想知道我的实现是否真的是糟糕的设计,并且有一种不同的,更清洁的方法。或者视图模型的用户不应该await
方法的结果?
答案 0 :(得分:4)
我对此方法的问题是Task的返回类型。显然,不应该等待该方法 - 它是无限循环并且一直运行直到发现停止。
那么我应该将其改为无效吗?但是这会违反async / await原则,其中void只能用于事件。
我不建议将其设为async void
方法。您可以将其保留为async Task
,仍然await
。
虽然Task
永远不会完成,但如果您在永无止境的任务中收到异常,那么将其包裹在await
内仍然会带来好处,例如自动异常传播(在正确的上下文中) 。如果您在某个时候选择这样做,这也可以让您提供正确的处理取消。
每当我遇到类似这样的话题时,我想知道我的实现是否真的是糟糕的设计,并且有一种不同的,更清洁的方法。或者视图模型的用户是否应该等待方法的结果?
在这种情况下,我实际上建议不要将其作为“异步”方法。使其成为异步方法的问题在于,异步方法会建议您现在正在初始化的某些操作,但最终会完成。 “永无止境”的异步方法会让这个API的用户感到困惑。
在内部,您可能希望保留一个类似的方法,但通过以下方式公开API:
public void StartAppInstanceDiscoveryService();
public event ExceptionEventHandler DiscoveryErrorReceived; // To propogate back an exception/error case if this fails?