c# - 构造函数中类字段的长时间运行初始化

标签 c# asynchronous constructor synchronous

假设我有下面的类(class)

public class MyClass {
    private readonly NinjaObject _myNinja;

    MyClass(NinjaFactory ninjaFactory) {
        _myNinja = ninjaFactory.CreateNinjaButItTakesTime();
    }

    public void NinjaAttack() {
        _myNinja.Attack();
    }
}

现在,构造函数应该做所有事情来初始化类并准备好供应用程序使用,即创建 Ninja 并准备好在调用时进行攻击。让您的构造函数快速执行操作也是一个好主意。但是,如果创建 Ninja 的过程需要很长时间,这可能是不可能的。我假设您可以通过某种静态工厂方法异步创建 Ninja,但是当应用程序调用 Ninja 时,您会冒着 Ninja 未准备好(即空对象)进行攻击的风险(至少在理论上)。

如果类的字段对该类的操作方式至关重要,但可能需要很长时间才能构建,那么创建它们的最佳模式是什么?在构造函数中保持同步,还是应用某种异步模式?

最佳答案

I presume you could create the Ninja asynchronously through some kind of static factory method, but then you run the risk (at least theoretically) of the Ninja not being ready (i.e. a null object) to attack when called to do so by the application.

好吧,这就是异步静态工厂方法派上用场的地方:

public class MyClass
{
    private readonly Ninja ninja;

    private MyClass(Ninja ninja)
    {
        this.ninja = ninja;
    }

    public static async Task<MyClass> Create()
    {
        // Or however you create a ninja - ideally properly asynchronous
        var ninja = await Ninja.Create();
        return new MyClass(ninja);
    }

    public void NinjaAttack() => ninja.Attack();
}

您无法避免它花费很长时间 - 但您可以通过将构造函数调用保留到最后来使创建异步。这基本上解决了构造函数不能异步的限制。

另一种选择——但也是一种危险的选择——是开始创建忍者的任务并将那个传递给构造函数,但稍后使用任务的结果:

public class MyClass
{
    private readonly Task<Ninja> ninjaTask;

    public MyClass(Task<Ninja> ninjaTask)
    {
        this.ninjaTask = ninjaTask;
    }

    public void NinjaAttack() => ninjaTask.Result.Attack();
}

这很危险,因为使用 Task<T>.Result在某些情况下可能会死锁,如果任务需要在完成之前在当前同步上下文中做更多的工作。您可以通过制作 NinjaAttack 来避免这种情况改为异步方法:

public class MyClass
{
    private readonly Task<Ninja> ninjaTask;

    public MyClass(Task<Ninja> ninjaTask)
    {
        this.ninjaTask = ninjaTask;
    }

    public async Task NinjaAttack() => (await ninjaTask).Attack();
}

根据您的上下文,您可能想要使用 await ninjaTask.ConfigureAwait(false) .

关于c# - 构造函数中类字段的长时间运行初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43026731/

相关文章:

ios - 无法从像 XMLParser 这样的异步函数调用 Segue

c# - .Net DownloadFileTaskAsync 健壮的 WPF 代码

c++ - 结构实例

c# - 下载数据时在 MonoTouch 中显示微调器

c# - Xamarin Forms 服务与 IsolatedProcess 崩溃

c# - 在 Visual Studio 的 LocalDB 中创建用户并为用户分配权限

c# - .Net Core 3 worker 服务应用程序,带有带参数的构造函数的插件

c# - 条件委托(delegate)?

python - 如何使用 django 发送异步电子邮件

php - 使用错误的输入初始化类会使其无法使用,但对象仍然存在