It's fairly established that doing work in ctors for types that are resolved using SimpleInjector is bad practice. Although this often leads to certain late initializations of such types, a particularly interesting case is Reactive Extensions subscriptions.
Take for instance an observable sequence that exhibits Replay(1) semantics (actually BehaviorSubject if we take the StartWith into account), e.g.
private readonly IObservable<Value> _myObservable;
public MyType(IService service)
{
_myObservable = service.OtherObservable
.StartWith(service.Value)
.Select(x => SomeTransform())
.Replay(1)
.RefCount();
}
public IObservable<Value> MyObservable => _myObservable;
Assume now, that SomeTransform is computationally expensive. From the point of view of SimpleInjector, the above is bad practice. Ok, so we need some kind of Initialize() method to call after SimpleInjector is finished. But what about our replay semantics and our StartWith()? Our consumers expect a value when they Subscribe (assume now that this is guaranteed to happen after initialization)!
How do we get around these restrictions in a nice way while still satisfying SimpleInjector? Here's a summary of requirements:
- Don't do extensive work in the ctor (i.e.
SomeTransform) should not run _myObservableshould bereadonlyMyObservableshould exhibitReplay(1)semantics- We should always have an initial value (hence the
StartWith) - We do not want to
SubscribeinsideMyTypeand cache the value (we like immutability)
I experimented with creating an additional observable that starts with false and then gets set to true on initialize, and then merging that together with _myObservable, but couldn't quite get it to work. Additionally, it doesn't seem like the best solution. In essence, all I want to do is delay until Initialize() is done. There must be some way to do this that I'm not seeing?
SomeTransform();is not called during the constructor. It is used when someone is actually using theMyObservableproperty. - ProgmanSomeTransform()actually be invoked from within the constructor, or does that only happen when that other service pushes a value? - Steven