1
votes

I Have three generic interfaces

public interface IRepositorioBase<T> where T : class {    }
public interface IServiceBase<T> where T : class {}
public interface IAppBase<T> where T : class {}

for which I have three corresponding concrete generic class implementations

public class RepositorioBase<T> where T : class {    }
public class ServiceBase<T> where T : class {}
public class AppBase<T> where T : class {}

and the other class are create using the class generics, example

public class ExpenseCardRepository : RepositoryBase<ExpenseCard>, IExpenseCardRepository{ }

public class ExpenseCardService : ServiceBase<ExpenseCard>, IExpenseCardService
{
    private readonly IExpenseCardRepository _repository;

    public ExpenseCardService(IExpenseCardRepository repository) : base(repository)
    {
        _repository = repository;
    }
}

public class ExpenseCardApp : AppBase<ExpenseCard>, IExpenseCardApp
{
    private readonly IExpenseCardService _service;

    public ExpenseCardApp(IExpenseCardService service) : base(service)
    {
        _service = service;
    }
}

I would like a generic code only to bind all types of interfaces depending on the type of class it inherits

These is example Ninject-Generic-Interface but I would like get of subclass.

1
Did you mean you are looking to register open generic types, as in the following hypothetical example that does not represent any Ninject syntax. Configure.Container(x => x.Register(typeof(IRepository<>), typeof(Repository<>)); - Alex
you're missing the definition of IExpenseCardRepository (here, in this example). Also the definition of IExpenseCardApp. - BatteryBackupUnit
In my opinion, having specific interfaces for your repository such as IExpenseCardRepository is a design smell, violates SOLID and leads to maintainability issues. Take a look at this article where this is explained. - Steven

1 Answers

6
votes

What you're trying to achieve can only be done by creating an explicit binding for each type. After all IExpenseCardRepository : IRepositoryBase<ExpenseCard> is different from ICustomerRepository : IRepositoryBase<Customer>. Now the good news is that you can automate this kind of work, by using Ninject.Extension.Convention. If you stick to a naming convention, it can be done very easy. The naming convention is: Class name ends with the interface name (without a leading I of course). From your code it looks like you do. Then the solution is as easy as:

kernel.Bind(x => x.FromThisAssembly()
    .SelectAllClasses()
    .InheritedFrom(typeof(IServiceBase<>))
    .BindDefaultInterfaces());

This will bind ExpenseCardService to IExpenseCardService and IServiceBase<ExpenseCard>.


If you don't adhere to this naming convention, then things get a little more complicated: you'll have to provide (customize) the binding creation part yourself. What you would have to do is implement an IBindingGenerator and use the .BindWith<MyBindingGenerator>() extension:

kernel.Bind(x => x.FromThisAssembly()
                  .SelectAllClasses()
                  .InheritedFrom(typeof(IRepositorioBase<>))
                  .BindWith<MyBindingGenerator>());

Your binding generator would then have to decide which types to bind to and create and return those bindings.


I have to give a word of caution, though: in most cases when i've seen this kind of design it was not necessary (there was a simpler solution available). In general you should favor composition over inheritance.