如何使用异步模式等待初始化对象 [英] How to initialize an object using async-await pattern

查看:195
本文介绍了如何使用异步模式等待初始化对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图按照RAII模式在我的服务类,这意味着当一个对象被构造,它完全初始化。不过,我面临着异步API的困难。有关类的结构看起来像下面

I'm trying to follow RAII pattern in my service classes, meaning that when an object is constructed, it is fully initialized. However, I'm facing difficulties with asynchronous APIs. The structure of class in question looks like following

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 吸气摆脱副作用,使其线程安全的。

I'm also targeting to get rid of side-effects in ImportantValue getter, to make it thread-safe.

现在的ServiceProvider 的用户将创建它的一个实例,订阅 ImportantValue 变化的事件,并获得最初的 ImportantValue 。在这里,问题来了,与初始值。因为 ImportantValue 异步计算,类不能被完全初始化的构造函数。这可能是好的最初有这个值为null,但我需要有一些地方,它会被计算第一次。对于自然的地方可能是 ImportantValue 的吸气剂,但我目标,使其线程安全的,无副作用。

Now users of ServiceProvider will create an instance of it, subscribe to an event of ImportantValue change, and get the initial ImportantValue. And here comes the problem, with the initial value. Since the ImportantValue is calculated asynchronously, the class cannot be fully initialized in constructor. It may be okay to have this value as null initially, but then I need to have some place where it will be calculated first time. A natural place for that could be the ImportantValue's getter, but I'm targeting to make it thread-safe and with no side-effects.

所以我基本上坚持了这些矛盾。能否请你帮我提供一些选择?具有构造函数初始化值,而漂亮的是不是真的有必要,但物业没有副作用和线程安全是必须的。

So I'm basically stuck with these contradictions. Could you please help me and offer some alternative? Having value initialized in constructor while nice is not really necessary, but no side-effects and thread-safety of property is mandatory.

先谢谢了。

编辑:还有一点要补充。我使用Ninject的实例,而据我了解,它不支持异步方法来创建一个绑定。同时与启动了在构造函数中的一些基于任务的操作方法将工作,我不能等待它的结果。

One more thing to add. I'm using Ninject for instantiation, and as far as I understand, it doesn't support async methods to create a binding. While approach with initiating some Task-based operation in constructor will work, I cannot await its result.

即。两个下的方法(如提供答案到目前为止)将无法编译,因为返回的任务,不是我的对象:

I.e. two next approaches (offered as answers so far) will not compile, since Task is returned, not my object:

Kernel.Bind<IServiceProvider>().ToMethod(async ctx => await ServiceProvider.CreateAsync())

Kernel.Bind<IServiceProvider>().ToMethod(async ctx => 
{
    var sp = new ServiceProvider();
    await sp.InitializeAsync();
})

简单的绑定工作,但我不会等待异步初始化的结果开始构造的提议,由斯蒂芬·克利里:

Simple binding will work, but I'm not awaiting the result of asynchronous initialization started in constructor, as proposed by Stephen Cleary:

Kernel.Bind<IServiceProvider>().To<ServiceProvider>();

...这不是我看起来很不错。

... and that's not looking good for me.

推荐答案

我有一个描述的几种方法异步建设

I have a blog post that describes several approaches to async construction.

我推荐的异步工厂方法励描述的,但有时这是不可能的(例如,依赖注入)。在这种情况下,你可以使用异步初始化模式是这样的:

I recommend the asynchronous factory method as described by Reed, but sometimes that's not possible (e.g., dependency injection). In these cases, you can use an asynchronous initialization pattern like this:

public sealed class MyType
{
    public MyType()
    {
        Initialization = InitializeAsync();
    }

    public Task Initialization { get; private set; }

    private async Task InitializeAsync()
    {
        // Asynchronously initialize this instance.
        await Task.Delay(100);
    }
}

您可以再构造型正常,但请记住,只有建设的启动的异步初始化。当您需要的类型进行初始化,您的code可以这样做:

You can then construct the type normally, but keep in mind that construction only starts the asynchronous initialization. When you need the type to be initialized, your code can do:

await myTypeInstance.Initialization;

请注意,如果初始化已经完成,执行(同步)延续了以往的的await

Note that if Initialization is already complete, execution (synchronously) continues past the await.

如果你想要做一个实际的异步财产,我有一个博客帖子说, 。太你的情况听起来可能受益 AsyncLazy&LT; T&GT;

If you do want an actual asynchronous property, I have a blog post for that, too. Your situation sounds like it may benefit from AsyncLazy<T>:

public sealed class MyClass
{
    public MyClass()
    {
        MyProperty = new AsyncLazy<int>(async () =>
        {
            await Task.Delay(100);
            return 13;
        });
    }

    public AsyncLazy<int> MyProperty { get; private set; }
}

这篇关于如何使用异步模式等待初始化对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆