NInject с универсальным интерфейсом

Я определил один интерфейс и один класс:

public interface IRepository<T>
{
}

public class RoleRepository:IRepository<Domain_RoleInfo>
{
}

Залить сюда:

public RoleService
{
    [Inject]
    public RoleService(IRepository<Domain_RoleInfo> rep)
    {
        _roleRep=rep;
    }
}

Как я могу выполнить инъекцию зависимостей с помощью Ninject, скажем, как связать?

Я написал вспомогательный класс, как показано ниже, он отлично работает с неуниверсальным интерфейсом. Но как реорганизовать его для поддержки универсального интерфейса, как указано выше?

public class RegisterNinjectModule : NinjectModule
{
    public override void Load()
    {
        BindServices();
        BindRepositories();
    }

    private void BindServices()
    {

        FindAndBindInterfaces("RealMVC.Service.Interfaces", "RealMVC.Services");            
    }

    private void BindRepositories()
    {
        FindAndBindInterfaces("RealMVC.Repository.Interfaces", "RealMVC.Repositories");   
    }

    private void FindAndBindInterfaces(string interfaceAssemblyName, string implAssemblyName)
    {
        //Get all interfaces
        List<Type> interfaces = Assembly.Load(interfaceAssemblyName).GetTypes().AsQueryable().Where(x => x.IsInterface).ToList();
        IQueryable<Type> ts = Assembly.Load(implAssemblyName).GetTypes().AsQueryable().Where(x => x.IsClass);

        foreach (Type intf in interfaces)
        {
            Type t = ts.Where(x => x.GetInterface(intf.Name) != null).FirstOrDefault();
            if (t != null)
            {
                Bind(intf).To(t).InSingletonScope();
            }
        }
    }


}

person Sam Zhou    schedule 07.02.2010    source источник


Ответы (4)


Это должно работать: -

Bind(typeof(IRepository<>)).To(typeof(Repository<>));

где:-

IRepository‹> — это интерфейс вида: —

public interface IRepository<T> where T : class
{
 //...
}

Репозиторий‹> — это класс следующего вида:

public class Repository<T> : IRepository<T> where T : class
{
  //...
}

Надеюсь, это поможет :-)

person Izmoto    schedule 11.03.2010
comment
Как будет выглядеть инъекция конструктора? - person chobo2; 06.06.2011
comment
Да, я пробовал с этим. Класс where T : определенно обязателен. - person Pilsator; 03.01.2013
comment
Обратите внимание, что если IRepository/Repository имеет более 1 аргумента типа, вам необходимо добавить соответствующее количество запятых в привязку, например. для 2 аргументов типа используйте Bind(typeof(IRepository<,>)).To(typeof(Repository<,>)); - person LeopardSkinPillBoxHat; 21.05.2014
comment
Это было очень полезно. - person Vahid Amiri; 03.11.2015

Это должно помочь выполнить то, о чем вы просите.

Сначала определим два класса (InterfaceTypeDefinition и BindingDefinition).

InterfaceTypeDefinition содержит информацию о конкретном типе и его интерфейсах. Метод IsOpenGeneric определен в классе TypeExtensions.

public class InterfaceTypeDefinition
{
    public InterfaceTypeDefinition(Type type)
    {
        Implementation = type;
        Interfaces = type.GetInterfaces();
    }

    /// <summary>
    /// The concrete implementation.
    /// </summary>
    public Type Implementation { get; private set; }

    /// <summary>
    /// The interfaces implemented by the implementation.
    /// </summary>
    public IEnumerable<Type> Interfaces { get; private set; }

    /// <summary>
    /// Returns a value indicating whether the implementation
    /// implements the specified open generic type.
    /// </summary>
    public bool ImplementsOpenGenericTypeOf(Type openGenericType)
    {
        return Interfaces.Any(i => i.IsOpenGeneric(openGenericType));
    }

    /// <summary>
    /// Returns the service type for the concrete implementation.
    /// </summary>
    public Type GetService(Type openGenericType)
    {
        return Interfaces.First(i => i.IsOpenGeneric(openGenericType))
            .GetGenericArguments()
            .Select(arguments => openGenericType.MakeGenericType(arguments))
            .First();
    }
}

BindingDefinition содержит информацию о привязке между службой и конкретной реализацией.

public class BindingDefinition
{
    public BindingDefinition(
        InterfaceTypeDefinition definition, Type openGenericType)
    {
        Implementation = definition.Implementation;
        Service = definition.GetService(openGenericType);
    }

    public Type Implementation { get; private set; }

    public Type Service { get; private set; }
}

Во-вторых, давайте реализуем метод расширения, который извлекает необходимую информацию.

public static class TypeExtensions
{
    public static IEnumerable<BindingDefinition> GetBindingDefinitionOf(
      this IEnumerable<Type> types, Type openGenericType)
    {
        return types.Select(type => new InterfaceTypeDefinition(type))
            .Where(d => d.ImplementsOpenGenericTypeOf(openGenericType))
            .Select(d => new BindingDefinition(d, openGenericType));
    }

    public static bool IsOpenGeneric(this Type type, Type openGenericType)
    {
        return type.IsGenericType 
            && type.GetGenericTypeDefinition().IsAssignableFrom(openGenericType);
    }
}

Эти классы теперь можно использовать для инициализации привязок в модуле.

public class RepositoryModule : NinjectModule
{
    public override void Load()
    {
        var definitions = Assembly.GetExecutingAssembly().GetTypes()
            .GetBindingDefinitionOf(typeof(IRepository<>));

        foreach (var definition in definitions)
        {
            Bind(definition.Service).To(definition.Implementation);
        }
    }
}
person mrydengren    schedule 07.02.2010
comment
Спасибо. это именно то, что я искал, когда задавал этот вопрос - stackoverflow.com/questions/11702477/ В TypeExtensions.GetBindingDefintionOf() есть одна опечатка - вы должны передать 'd' вместо 'definition' при создании BindingDefinition в методе Select. - person Baldy; 28.07.2012

Если вы импортируете расширение конвенций Ninject, его GenericBindingGenerator должно вам помочь. Он добавляет поддержку общих интерфейсов.

person neontapir    schedule 03.03.2011

Просто вопрос по вашему методу FindAndBindInterfaces: внутри foreach нет ли у вас проблемы с "закрытием" переменной intf? Я все еще не уверен, что понял, как работает проблема с закрытием.

В любом случае, на всякий случай, я думаю, вам следует изменить свой foreach на что-то вроде:

foreach (Type intf in interfaces)
    {
        var tmp = intf;
        Type t = ts.Where(x => x.GetInterface(tmp.Name) != null).FirstOrDefault();
        if (t != null)
        {
            Bind(intf).To(t).InSingletonScope();
        }
    }
person Ghidello    schedule 29.05.2010