2

Closed

Add the missing RegisterSingle(Type concreteType)

description

Once upon a time, in the early days, the SimpleInjector.Extensions project contained a
“RegisterSingle(this Container, Type)” extension method, which allowed users to register a concrete type (by itself) as singleton. Users would write the following:
 
container.RegisterSingle(typeof(SomeType));
 
Which was expected to be the equivalent of:
 
container.RegisterSingle<SomeType>();
 
C# overload resolution however, always picks instance methods over extension methods (when one is applicable), and the C# compiler would turn this into:
 
container.RegisterSingle<Type>(typeof(SomeType));
 
Which means something completely different. The nasty thing however was, that IntelliSense in the IDE showed this method, which lead users to think that they could actually use this method, while a complete different registration was made. This extension methods was therefore removed from the extensions library.
 
Unfortunately there is currently no real good alternative for registering a single concrete type in a late bound fashion (using a Type).
 
There are basically three options:
 
  1. Add it again in the Extensions package, which is the most logical thing to do, since the this package contains all late bound stuff. This does mean however that a different name has to be chosen, to prevent the C# compiler from picking the wrong method. Something like 'RegisterSingleConcrete'. This however, is not intuitive, since all other methods are named RegisterSingle.
     
  2. Add it as instance method to the Container in the core library. This way we can keep the name 'RegisterSingle'. This does however 'pollute' the core API with a late bound registration method, which could also confuse starting developers.
     
  3. Abuse the current Container.RegisterSingle<TService>(TService) instance method to do a check if the given TService is of type Type, and call Container.RegisterSingle<TService>() under the covers. This seems like a clean solution, and when adding a ‘dummy’ RegisterSingle(Type) extension method in the extensions project, we could even have it pop-up during IntelliSense. But this is a bit of voodoo, and it will worry more advanced users that understand more about C# overload resolution (or when they do ‘goto definition’ on that method in the IDE.
Closed Jul 14, 2012 at 5:43 PM by dot_NET_Junkie
Fixed with check in 92812.

comments

dadhi wrote Jul 8, 2012 at 10:37 AM

I have tried to implement attribute based registration for scanned assembly in order to migrate from MEF attributed model and was very happy until completely stuck with such a "minor" matter.
In my oppinion, this functionaly is most have to provide complete feature set and right now it looks like a hole in API.

1st option is looking good.

Another alternative would be to allow serviceType and implementation type be the same in Register/RegisterSingle methods. You can switch to corresponding implementation internally if there was some specific reason behind the similarity check. Personally I prefer this approach because it was where I stuck at the first place.

dot_NET_Junkie wrote Jul 8, 2012 at 1:52 PM

A workaround to to use the Register(Container, Type, Func<object>) overload and register a Func<object> that always returns the same object:

object singleton = new SomeServiceImpl();
container.Register(serviceType, () => singleton);

dot_NET_Junkie wrote Jul 14, 2012 at 5:32 PM

@dadhi. Allowing the service type and implementation type to be the same is actually a very good idea. Although this breaks with the API design of the core library, this is actually the best option. This is how I will implement this in the next release.

wrote Jul 14, 2012 at 5:41 PM

Resolved with changeset 92812.