42 votes

NInject avec interface générique

J'ai défini une interface et une classe:

 public interface IRepository<T>
{
}

public class RoleRepository:IRepository<Domain_RoleInfo>
{
}
 

Injecter ici:

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

Comment effectuer une injection de dépendance avec Ninject, comment lier?

J'ai écrit une classe d'assistance comme ci-dessous, elle fonctionne bien avec une interface non générique. Mais comment la refactoriser prend-elle en charge une interface générique comme ci-dessus?

 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();
            }
        }
    }


}
 

81voto

Izmoto Points 1134

Cela devrait fonctionner: -

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

où:-

IRepository <> est une interface de la forme: -

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

Repository <> est une classe de la forme: -

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

J'espère que ça aide :-)

5voto

mrydengren Points 3319

Cela devrait aider à accomplir ce que vous demandez.

Laissez-nous d'abord de définir deux classes (InterfaceTypeDefinition et BindingDefinition).

InterfaceTypeDefinition détient des informations sur un type de béton et de ses interfaces. La méthode IsOpenGeneric est de définir dans l' TypeExtensions classe.

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 détient des informations sur la liaison entre un service et une mise en œuvre concrète.

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; }
}

Deuxièmement, permettez-nous de mettre en œuvre une méthode d'extension qui permet de récupérer les informations nécessaires.

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);
    }
}

Ces classes peuvent maintenant être utilisés pour initialiser les liaisons dans le module.

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);
        }
    }
}

2voto

neontapir Points 2692

Si vous importez l'extension Ninject conventions, son GenericBindingGenerator devrait pouvoir vous aider.

0voto

Ghidello Points 66

Juste une question sur votre méthode FindAndBindInterfaces : dans le foreach, n’avez-vous pas un problème de "fermeture" sur la variable intf ? Je ne suis toujours pas sûr d'avoir compris comment fonctionne le problème de la fermeture.

Quoi qu'il en soit, juste pour être en sécurité, je pense que vous devriez changer votre foreach en quelque chose comme:

 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();
        }
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X