我有以下内容:
public interface IConverter<TValue, TConverted>
{
}
public interface IConverterProvider
{
IConverter<TValue, TConverted> GetConverter<TValue, TConverted>();
}
在设置时使用示例绑定:
Bind<IConverter<System.Int32, System.String>>().To<Int32ToStringConverter>();
Bind<IConverter<System.Guid, System.String>>().To<GuidToStringConverter>();
所以我有一组固定的转换器,没有重复的绑定。
[问题] 我的问题是如何实现IConverterProvider并注入映射到单例的可用绑定字典?或者换句话说,如何避免运行时服务定位器模式。
目前我只是使用NInject内核来解决每次问题,但我相信这是一种反模式。我想要的是这样的:
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();
}
}
但这有效地要求我能够解析并获得所有IConverter&lt;,&gt;的列表。从依赖注入内核,我之前从NInject做这件事的尝试都没有成功。
答案 0 :(得分:1)
Bind<IConverter<System.Int32, System.String>>().To<Int32ToStringConverter>();
Bind<IConverter<System.Guid, System.String>>().To<GuidToStringConverter>();
Bind<IConverterProvider>().ToFactory();
无需实施
将GetConverter
重命名为CreateConverter
或其他不以Get
答案 1 :(得分:0)
我通常用这样的东西建立一个工厂(或你在这里的提供者):
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);
}
}
我知道我们并不是真的应该使用Ninject在运行时创建东西,但实际上有时它是不可避免的。要获得单例行为,只需将InSingletonScope()
定义为正常。
如果类型不是通用的,那么你可以注入接口的所有实现而不是IResolutionRoot
,然后在运行时选择一个。我有一个像这样的解析器工厂:
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将自动注入包含接口所有具体实现的IEnumerable
,因此添加新实现就像添加映射一样简单。我不知道如何使用泛型类型,因为你不能说IEnumerable<IConverter<,>>
。