Ninject-关于绑定通用工厂的问题

时间:2019-06-03 14:12:30

标签: ninject

我有一个实现不同类的接口“ IItemsChanger”。

public interface IItemsChanger
{
    void Change(int value)
}

一个可能的实现是一个简单的类,该类接收可能不同的item对象:

public class MyItemChanger : IItemChanger
{
    private readonly IEnumerable<MyItem> _items;

    public ArticoliStateChanger(IEnumerable<MyItem> items)
    {
        _items = items;
    }

    public void Change(int value)
    {
        ...
    }
}

如您所见,构造函数的IEnumerable为MyItem;在另一个实现中,可以将MyItem替换为另一个IEnumerable。

我想在实现中通过构造函数注入MyItem的列表,因此我需要建立一个工厂。 由于项目可以采用不同的类型,因此我还需要保持工厂为通用类型,例如:

public interface IItemsChangerFactory<T>
{
    IItemsChanger Create(IEnumerable<T> items);
}

如果这有道理,我就这样配置Ninject:

Bind(typeof(IItemsChangerFactory<>)).ToFactory();
Bind<IItemsChanger>().To<MyItemChanger>();

当我尝试获得这样的实现时:

var kernel = new StandardKernel(new MyModule());
var k = kernel.Get<IItemsChangerFactory<MyItem>>();

我得到一个错误:

“无法将类型为“ Castle.Proxies.ObjectProxy”的对象转换为类型为“ MyNamespace.IItemsChangerFactory`1 [MyItem]”

如何解决?

1 个答案:

答案 0 :(得分:0)

Ninject或Ninject.Extensions.Factory都不支持此问题。 问题在于Ninject或工厂都不知道如何将T的{​​{1}} Type参数映射到特定的IItemsChangerFactory<T>实现。该逻辑需要由您编写。

现在是下一个问题。您不能具有接口类型构造函数,即您不能声明IItemsChanger的构造函数来实现MyItemChanger。您可以编写为编译时安全的代码,但需要一些样板代码,即:

IItemsChangerFactory<MyItem>

或者您可以使用反射-但会丢失编译时间检查:

class MyItemChangerFactory : IItemsChangerFactory<MyItem>
{
    public IItemsChanger Create(IEnumerable<T> items)
    {
        return new MyItemChanger(items);
    }
}

当然可以用以下方式代替class ItemChangerFactory<TItem, TChanger> : IItemsChangerFactory<TItem> { public IItemsChanger Create(IEnumerable<T> items) { return Activator.CreateInstance(typeof(TChanger), new object[] { items }); } } :n Activator