Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Rename RegisterSingleton<T>(T) to RegisterInstance #469
is equivalent to the following method when called with
container.Register<T>(Func<T> instanceCreator, Lifestyle lifestyle);
An API that offers two different ways of accomplishing the same thing isn't ideal, and wouldn't be a huge problem until we consider this other overload, with different semantics. This one registers a pre-created instance outside of the control of the container:
The docs say:
Registering a pre-created instance is of course a valid requirement, but is relatively rare.
Registering a container-controlled singleton is a very common requirement, but we already have a way of doing this with the
The reason I raise this concern is because I'm currently migrating a codebase from Unity to Simple Injector, and I see their equivalent method
unityContainer.RegisterInstance<IMyService>(new MyService(), new ContainerControlledLifetimeManager());
unityContainer.RegisterType<IMyService, MyService>(new ContainerControlledLifetimeManager());
I will be fixing all these registrations during the migration process, but as we have a large team, I am sure that old habits will die hard, and SI's
I'd would like to discuss
Overall, does it satisfy these two design principles?
You raise fair points. Let's first establish that creating an intuitive API is hard, really hard. Especially when we consider that what one may find intuitive, can be confusing for others. A good example of this is when developers migrate from some other container to Simple Injector. They find Simple Injector's behavior unintuitive, since they are simply used to the work of other containers.
We actually did try to get rid of the redundant
It depends on how you look at it. It might make more sense if you take the following rule into consideration:
This is a very basic design principle that holds, even outside the context of Simple Injector, or even outside the context of DI.
In this sense, Simple Injector assumes the instances created by factories to be created (and thus owned) by itself, while it assumes an instance supplied to Simple Injector 'externally owned'.
Such rule however is very hard to express succinctly in any API. Removing
There is a balance between succinct naming and intuitively. Although long names might be more intuitive to a first-time user, it will annoy long-time users, and will get in the way when you have big DI configurations. The choice has been made in the past to get rid of
Just like we tried getting rid of
So steps will be taken, but as some evil men once said: "the process of transformation, even if it brings revolutionary change, is likely to be a long one".
Thanks for your thoughtful response, and for illuminating me on the history of this method.
If the long term plan is to remove
When it comes to removing 'things' the strategy typically is:
Marking something Obsolete, even Obsolete(false) must be considered a breaking change, but that has never prevented us from doing this in case we feel the benefits outweighs the trouble. In other cases we might do the Obsolete(false) on a major release, Obsolete(true) on the following major and remove it completely in major+2, but I don't think we actually did that with Simple Injector. But once your user base grows, you have obviously to be more careful.