4

我有以下内容:

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<,> 的列表,而我之前从 NInject 执行此操作的尝试没有成功。

4

2 回答 2

1

这得到了支持Ninject.Extensions.Factory

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

无需实施

重命名GetConverterCreateConverter或其他不以 Get 开头的名称

于 2013-02-28T21:53:46.240 回答
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<,>>.

于 2013-02-27T20:35:19.523 回答