Próbuję wykonać wzór RAII w moich klasach usług, co oznacza, że po skonstruowaniu obiektu, jest on w pełni inicjalizowany. Jednak mam problemy z asynchronicznymi interfejsami API. Struktura klasy w pytaniu wygląda poJak zainicjować obiekt przy użyciu wzoru async-await
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
}
}
Jestem również kierowanie pozbyć się skutków ubocznych w ImportantValue
getter, aby thread-safe.
Teraz użytkownicy ServiceProvider
utworzą jego instancję, zasubskrybują wydarzenie o ImportantValue
zmianie i otrzymają wstępną ImportantValue
. I tu pojawia się problem z początkową wartością. Ponieważ ImportantValue
jest obliczany asynchronicznie, nie można w pełni inicjalizować klasy w konstruktorze. Może być w porządku, aby początkowo mieć tę wartość jako zerową, ale muszę mieć pewne miejsce, w którym zostanie ona obliczona po raz pierwszy. Naturalnym miejscem na to może być getter z ImportantValue
, ale zamierzam uczynić go bezpiecznym dla wątków i bez żadnych skutków ubocznych.
Więc zasadniczo utknąłem z tymi sprzecznościami. Czy możesz mi pomóc i zaoferować alternatywę? Posiadanie wartości zainicjowanej w konstruktorze, gdy jest ładne, nie jest tak naprawdę konieczne, ale żadne skutki uboczne i bezpieczeństwo nici własności nie są obowiązkowe.
Z góry dziękuję.
EDYCJA: Jeszcze jedna rzecz do dodania. Używam programu Ninject do tworzenia wystąpień i, o ile rozumiem, nie obsługuje on metod asynchronicznych w celu utworzenia powiązania. Chociaż podejście z zainicjowaniem niektórych operacji opartych na zadaniach w konstruktorze będzie działać, nie mogę czekać na jego wynik.
tj. Kolejne dwa podejścia (oferowane jako odpowiedzi tak daleko) nie będzie kompilować, ponieważ zadanie jest zwracany, a nie mojego obiektu:
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 jestem w oczekiwaniu na rezultatem asynchronicznego inicjalizacji rozpoczęła się w konstruktora, zaproponowane przez Stephen Cleary:
Kernel.Bind<IServiceProvider>().To<ServiceProvider>();
... i to nie wygląda dobrze dla mnie.
Nie sądzę, że to RAII. Prawdopodobnie najważniejszą częścią jest dealokacja zasobów (choć nazwa tego nie sugeruje). I tak naprawdę nie dotyczy to C#, ponieważ GC powoduje niedeterministyczną dealokację. – svick
Sprawdź moją bibliotekę [AsyncContainer] (https: // github.com/RafaelSalguero/AsyncContainer) – rafael