23

I'm fairly new to Ninject, and found myself stumbling when I came to implement a generic repository pattern. I want to bind a dependency IRepository<IEntityType> to a class ConcreteRepository<EntityType> where ConcreteRepository<T> implements IRepository<T> and EntityType implements IEntityType. I tried this:

kernel.Bind<IRepository<IEntityType>>().To<ConcreteRepository<EntityType>>();

...but Ninject won't take that because it doesn't know or care that EntityType implements IEntityType. How can I go about binding this dependency?

UPDATE

This is the error I'm getting:

Error 3 The type 'ICM.Dependency.Repository.ConcreteRepository' cannot be used as type parameter 'TImplementation' in the generic type or method 'Ninject.Syntax.IBindingToSyntax.To()'. There is no implicit reference conversion from 'ConcreteRepository<EntityType>' to 'IRepository<IEntityType>'.

SOLUTION

I still don't quite understand why my binding doesn't work, but evidently I was using generics incorrectly there. As such the solution doesn't really relate to NInject. I ended specifying the ConcreteRepository to explicitly connect IEntityType with TEntityType:

public class ConcreteRepository<TInterface, TEntity> : IRepository<TInterface> where TEntity : TInterface { ... }

Then the injection can be written as follows:

kernel.Bind<IRepository<IEntityType>>().To<ConcreteRepository<IEntityType,EntityType>>()
McGarnagle
  • 101,349
  • 31
  • 229
  • 260
  • What message are you getting? Is it a compile one or runtime? Does `ConcreteRepository` implement `IRepository` (Also, generally one would have the ctor dependency be on on `IRepository` - in which case your Bind above would be wrong. – Ruben Bartelink Apr 20 '12 at 20:05
  • @RubenBartelink It's a compile error; see update above. To your first point- it does not, but as mentioned ConcreteRepository implements IRepository. Maybe that's my issue. To your second point, I want to use IRepository in the constructor to allow for flexibility-- the repository dependency should deal with an interface, not concrete entities. – McGarnagle Apr 20 '12 at 20:25
  • Right. Well the `where` constraint that's causing the compile error is there for a reason - there simply is no way in which the concrete component type you're suggesting is going to be convertible to the service type you're `Bind`ing to so stop looking! I suggest looking at how others have implmented generic repository patterns - you're far away from normal practice. You could explain what you're getting from this stuff in your question here, but I'd suggest you should ask yourself first and then maybe here whether your class hierarchy can be rationalised. – Ruben Bartelink Apr 20 '12 at 22:29
  • @RubenBartelink That's as may be, but my question isn't how to implement a generic repository. It's how to bind a dependency to a generic interface. – McGarnagle Apr 20 '12 at 22:49
  • @dbaseman why are you wanting your concrete repository to take a concrete entity at all? couldn't it just take your entity interface? – undefined Apr 20 '12 at 23:15
  • Sorry for confusing matters by mixing opinion with what's needed for your question to make sense. I will concentrate on teh lattter now:- You've shown a compiler error; the compiler error makes sense - what you're asking doesnt make sense and could never work - be thankful its a compile time rather than runtime issue. Can you show excerpts of the resoluton target (i.e. where the injection is going into, and the entity and repository interfaces. As it stands, @Luke McGregor hasnt been able to answer you and I for one havent any idea what you're trying to achieve - its not like anything else. – Ruben Bartelink Apr 21 '12 at 00:01
  • @LukeMcGregor No, it has to bind to a concrete entity, because it binds to a data access class that needs to instantiate actual objects. – McGarnagle Apr 21 '12 at 00:39

1 Answers1

47
kernel.Bind(typeof(IRepository<>)).To(typeof(SimpleRepository<>));

Take a look at my one if you want here: http://blog.staticvoid.co.nz/2011/10/staticvoid-repository-pattern-nuget.html i have binding examples

EDIT:

The error you are getting is saying that your concrete repository isnt an instance of the generic one you want to bind to, ie you will need to do this

public class ConcreteRepository<ConcreteEntity> : IRepository<IEntity>{}

not

public class ConcreteRepository<ConcreteEntity> : IRepository<ConcreteEntity>{}
undefined
  • 33,537
  • 22
  • 129
  • 198
  • @RubenBartelink hmm i see what you mean, the issue is that the above scenario will work for binding `IRepository` to `ConcreteRepository` but not to `ConcreteRepository`. I'm not sure that there would be a way of producing this binding for all types in Ninject at all. To get this effect you would need to manually bind each repository. – undefined Apr 20 '12 at 23:11
  • Apologies for the confusion-- I was trying to simplify my use case by abstracting it, but I think that just obfuscated what I was trying to do. I basically implemented what you are suggesting; only I added a second type parameter to preserve the interface to the entity in the class definition. – McGarnagle Apr 21 '12 at 19:03
  • @dbaseman i actually quite like that, it means your concrete repository is a map between an abstract construct and a concrete one – undefined Apr 22 '12 at 02:00