类FeatureManager
管理一些功能,看起来像这样:
public class FeatureManager
{
public event EventHandler FeatureEnabledChangedEvent;
private void OnFeatureEnabledChanged()
{
if (FeatureEnabledChangedEvent != null)
{
FeatureEnabledChangedEvent(this, EventArgs.Empty);
}
}
public event EventHandler FeatureEnableBusyChangedEvent;
private void OnFeatureEnableBusyChanged()
{
if (FeatureEnableBusyChangedEvent != null)
{
FeatureEnableBusyChangedEvent(this, EventArgs.Empty);
}
}
public event EventHandler FeatureEnableFailedEvent;
private void OnFeatureEnableFailed(FeatureEnableFailedEventArgs args)
{
if (FeatureEnableFailedEvent!= null)
{
FeatureEnableFailedEvent(this, args);
}
}
private bool _isFeatureEnabled
public bool IsFeatureEnabled
{
get
{
return _isFeatureEnabled;
}
private set
{
if (_isFeatureEnabled != value)
{
_isFeatureEnabled = value;
OnFeatureEnabledChanged();
}
}
}
private bool _isFeatureEnableBusy;
public bool IsFeatureEnableBusy
{
get
{
return _isFeatureEnableBusy;
}
private set
{
if (_isFeatureEnableBusy != value)
{
_isFeatureEnableBusy = value;
OnFeatureEnableBusyChanged();
}
}
}
public async Task EnableFeature()
{
IsFeatureEnableBusy = true;
try
{
// By its nature, process of enabling this feature is asynchronous.
await EnableFeatureImpl(); // can throw exception
IsFeatureEnabled = true;
}
catch(Exception exc)
{
OnFeatureEnableFailed(new FeatureEnableFailedEventArgs(exc.Message));
}
finally
{
IsFeatureEnableBusy = false;
}
}
}
在以下情况下必须通知 UI类FeatureView
IsFeatureEnableBusy
更改(或者,换句话说,正在执行EnableFeature
时 - 为了禁用某些控件)IsFeatureEnabled
更改EnableFeature
失败(当它抛出异常时,FeatureView
显示错误消息
给用户) EnableFeature
可以从某个引擎类E
(在应用程序初始化期间自动启动)和FeatureView
(当用户按下&#39时)调用;启用'按钮)。
为了满足FeatureView
在EnableFeature
调用后E
失败时必须通知的要求,我添加了一个事件FeatureEnableFailedEvent
。
当E
调用EnableFeature
而EnableFeature
引发异常时,FeatureView
会收到FeatureEnableFailedEvent
并显示错误消息。但是当FeatureView
本身调用EnableFeature
和EnableFeature
失败时,FeatureView
会捕获抛出的异常,但也会从FeatureEnableFailedEvent
收到有关此失败的通知,因此会调用错误处理程序两次。 如何避免这种情况?
一种解决方案是将EnableFeature
声明为旧式异步方法(并使用 BackgroundWorker ),如下面的代码段所示:
public class FeatureManager
{
public void EnableFeatureAsync()
{
var bgw = new BackgroundWorker();
bgw.DoWork += (sender, e) =>
{
IsFeatureEnableBusy = true;
EnableFeatureImpl(); // can throw exception
};
bgw.RunWorkerCompleted += (sender, args) =>
{
IsFeatureEnableBusy = false;
if (args.Error == null)
{
IsFeatureEnabled = true;
}
else
{
OnFeatureEnableFailed(new FeatureEnableFailedEventArgs(args.Error.Message));
}
};
bgw.RunWorkerAsync();
}
}
在这种情况下,EnableFeatureAsync
的调用者可以假设此方法异步运行(方法&名称中的后缀 Async 应该是一个提示)并且它必须订阅如果想要通知方法失败,请FeatureEnableFailedEvent
。这样FeatureView
只会在EnableFeatureAsync
失败时收到通知,因此错误处理程序会被调用一次。
这是一个好方法吗?这可以通过仍然以某种方式使用async / await来实现吗?是不是假设方法名称中的后缀 Async 对调用者来说是一个足够好的提示,因此他们知道这个方法以异步方式运行,并且他们必须查找一些事件来订阅吗
答案 0 :(得分:0)
正如@svick评论的那样,我也不明白为什么你的FeatureView
会抓住异常并且在FeatureManager
的处理程序中没有重新抛出异常时也会得到事件。但这是一种不同的方法,我更喜欢基于事件的方法:
使用TaskCompletionSource让视图知道功能的启用何时引发异常,即使FeatureView
不是EnableFeature()
的调用者(顺便说一句,按照惯例,该方法也应该在第一个例子中命名为EnableFeatureAsync。
public class FeatureManager
{
public TaskCompletionSource<bool> FeatureCompleted { get; private set; }
// if you still need this property
public bool IsFeatureEnabled
{
get { return FeatureCompleted.Task.IsCompleted; }
}
public FeatureManager() {}
public async Task EnableFeature()
{
IsFeatureEnableBusy = true;
try
{
// By its nature, process of enabling this feature is asynchronous.
await EnableFeatureImpl(); // can throw exception
this.FeatureCompleted.TrySetResult(true);
}
catch(Exception exc)
{
this.FeatureCompleted.TrySetException(exc);
}
finally
{
IsFeatureEnableBusy = false;
}
}
}
您的FeatureView
实例现在需要等待TaskCompletionSource的任务。代码可能如下所示:
public class FeatureView
{
// if you still need this property
public async void HandleFeatureCompleted(FeatureManager fm)
{
try
{
await fm.FeatureCompleted.Task;
}
catch(Exception e)
{
// handle exception
}
}
}
您必须在视图中提供正确的FeatureManager
实例。如果您有百分之一甚至数千个FeatureManager
实例消息,我不确定这种方法是否合适。如果评论者中有更多人可以就此提供反馈,我会很高兴。