Jak zainicjować obiekt za pomocą wzorca asynchronicznego oczekiwania

Próbuję podążać za wzorcem RAII w moich klasach usług, co oznacza, że ​​gdy obiekt jest konstruowany, jest w pełni inicjowany. Mam jednak problemy z asynchronicznymi interfejsami API. Struktura omawianej klasy wygląda następująco

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
    }
}

Mam również na celu pozbycie się efektów ubocznychImportantValue getter, aby był bezpieczny dla wątków.

Teraz użytkownicyServiceProvider utworzy jego wystąpienie, zasubskrybuje wydarzenieImportantValue zmienić i uzyskać początkowyImportantValue. I tu pojawia się problem z wartością początkową. OdImportantValue jest obliczany asynchronicznie, klasy nie można w pełni zainicjować w konstruktorze. Początkowo może mieć wartość null, ale muszę mieć miejsce, w którym będzie obliczane po raz pierwszy. Naturalnym miejscem na to może byćImportantValuegetter, ale zamierzam uczynić go bezpiecznym dla wątków i bez skutków ubocznych.

Tak więc zasadniczo utknąłem w tych sprzecznościach. Czy mógłbyś mi pomóc i zaproponować alternatywę? Posiadanie wartości zainicjowanej w konstruktorze, gdy ładne, nie jest naprawdę konieczne, ale nie są wymagane żadne efekty uboczne i bezpieczeństwo wątku.

Z góry dziękuję.

EDYTOWAĆ: Jeszcze jedna rzecz do dodania. Używam Ninject do tworzenia instancji i, o ile rozumiem, nie obsługuje asynchronicznych metod tworzenia powiązań. Chociaż podejście do inicjowania niektórych operacji opartych na zadaniach w konstruktorze będzie działać, nie mogę czekać na jego wynik.

To znaczy. dwa kolejne podejścia (dotychczas dostępne jako odpowiedzi) nie będą się kompilować, ponieważ zadanie jest zwracane, a nie mój obiekt:

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

lub

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

Proste wiązanie będzie działać, ale nie oczekuję wyniku asynchronicznej inicjalizacji rozpoczętej w konstruktorze, jak zaproponował Stephen Cleary:

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

... a to nie wygląda dobrze dla mnie.

questionAnswers(5)

yourAnswerToTheQuestion