Implementing a service locator with generic options introduced

I have the following:

public interface IConverter<TValue, TConverted> { } public interface IConverterProvider { IConverter<TValue, TConverted> GetConverter<TValue, TConverted>(); } 

With an example of binding when setting up:

 Bind<IConverter<System.Int32, System.String>>().To<Int32ToStringConverter>(); Bind<IConverter<System.Guid, System.String>>().To<GuidToStringConverter>(); 

So, I have a set of fixed converters and duplicates.

[Question] My question is, how do I go about implementing IConverterProvider and introduce a dictionary of available bindings mapped to singles? Or, in other words, how to avoid the locator service pattern at run time.

Currently, I just use the NInject kernel to resolve it every time, but I consider it an anti-pattern. I would like it to be like this:

 public class ConverterProvider : IConverterProvider { private Dictionary<Type, object> _converters; public ConverterProvider(Dictionary<Type, object> converters) { _converters = converters; } public IConverter<TValue, TConverted> GetConverter<TValue, TConverted>() { var fullTypeResolve = typeof (IConverter<,>).MakeGenericType(typeof (TValue), typeof (TConverted)); return _converters.Where(x => x.Key == fullTypeResolve).Select(x=>x.Value).Cast<IConverter<TValue, TConverted>>().Single(); } } 

But this really requires that I can resolve and get a list of all IConverter <,> from the dependency input kernel, and my previous attempts to do this from NInject were not successful.

+4
source share
2 answers

This is supported by Ninject.Extensions.Factory

 Bind<IConverter<System.Int32, System.String>>().To<Int32ToStringConverter>(); Bind<IConverter<System.Guid, System.String>>().To<GuidToStringConverter>(); Bind<IConverterProvider>().ToFactory(); 

No implementation required

Rename GetConverter to CreateConverter or another name not starting with Get

+1
source

I usually do a factory (or a provider like you are here), with something like this:

 public class ConverterFactory : IConverterFactory { private readonly IResolutionRoot resolutionRoot; public ConverterFactory(IResolutionRoot resolutionRoot) { this.resolutionRoot = resolutionRoot; } public IConverter<TValue, TConverted> CreateConverter() { Type converterType = typeof(IConverter<,>).MakeGenericType(typeof(TValue), typeof(TConverted)); return this.resolutionRoot.Get(converterType); } } 

I know that we should not use Ninject to create things at runtime, but in fact this is sometimes inevitable. To get singleton behavior, just define InSingletonScope() as usual.

If the types were not common, you can implement all the implementations of the interface instead of IResolutionRoot , and then select one at runtime. I have a factory parser something like this:

 public class ParserFactory : IParserFactory { private readonly IEnumerable<IParser> parsers; public ParserFactory(IEnumerable<IParser> parsers) { this.parsers = parsers; } public IParser CreateParser(string someInput) { foreach (var parser in this.parsers) { if (parser.CanParse(someInput)) { return parser; } } } } 

Ninject will automatically add an IEnumerable containing all the concrete implementations of the interface, so adding new implementations is as easy as adding a mapping. I do not know how to do this with generic types, although you cannot say IEnumerable<IConverter<,>> .

0
source

All Articles