我试图在我的服务类中遵循 RAII 模式,这意味着当一个对象被构造时,它会被完全初始化。但是,我在使用异步 API 时遇到了困难。有问题的类的结构如下所示
class ServiceProvider : IServiceProvider // Is only used through this interface
{
public int ImportantValue { get; set; }
public event EventHandler ImportantValueUpdated;
public ServiceProvider(IDependency1 dep1, IDependency2 dep2)
{
// IDependency1 provide an input value to calculate ImportantValue
// IDependency2 provide an async algorithm to calculate ImportantValue
}
}
我的目标还在于消除ImportantValue
getter 中的副作用,使其成为线程安全的。
现在 的用户ServiceProvider
将创建它的一个实例,订阅一个ImportantValue
更改事件,并获取初始的ImportantValue
. 问题来了,初始值。由于ImportantValue
是异步计算的,因此无法在构造函数中完全初始化该类。最初将此值设置为 null 可能没问题,但随后我需要有一些地方可以第一次计算它。一个自然的地方可能是ImportantValue
'getter,但我的目标是使其成为线程安全且没有副作用的。
所以我基本上被这些矛盾所困扰。你能帮助我并提供一些替代方案吗?在构造函数中初始化值虽然 nice 并不是真正必要的,但没有副作用和属性的线程安全是强制性的。
提前致谢。
编辑:还要添加一件事。我正在使用 Ninject 进行实例化,据我了解,它不支持异步方法来创建绑定。虽然在构造函数中启动一些基于任务的操作的方法会起作用,但我不能等待它的结果。
即两种下一个方法(到目前为止作为答案提供)将无法编译,因为返回的是 Task,而不是我的对象:
Kernel.Bind<IServiceProvider>().ToMethod(async ctx => await ServiceProvider.CreateAsync())
或者
Kernel.Bind<IServiceProvider>().ToMethod(async ctx =>
{
var sp = new ServiceProvider();
await sp.InitializeAsync();
})
简单的绑定将起作用,但我不等待在构造函数中启动的异步初始化的结果,正如 Stephen Cleary 所提出的:
Kernel.Bind<IServiceProvider>().To<ServiceProvider>();
......这对我来说并不好。