So this is how you could achieve it while still injecting IRepository<XYZ>
into the consumer:
public interface ISoftDeletable
{
}
public interface IPermanentDeleteable
{
}
public interface IRepository<TEntity>
{
}
public class PermanentDeletableRepository<TEntity> : IRepository<TEntity>
where TEntity : IPermanentDeleteable
{
}
public class SoftDeletableRepository<TEntity> : IRepository<TEntity>
where TEntity : ISoftDeletable
{
}
public class RepositoryModule : NinjectModule
{
public override void Load()
{
this.Bind(typeof(IRepository<>))
.To(typeof(PermanentDeletableRepository<>))
.When(IsRequestForRepositoryOfEntityImplementing<IPermanentDeleteable>);
this.Bind(typeof(IRepository<>))
.To(typeof(SoftDeletableRepository<>))
.When(IsRequestForRepositoryOfEntityImplementing<ISoftDeletable>);
}
public static bool IsRequestForRepositoryOfEntityImplementing<TInterface>(IRequest request)
{
Type entityType = GetEntityTypeOfRepository(request.Service);
return ImplementsInterface<TInterface>(entityType);
}
public static Type GetEntityTypeOfRepository(Type repositoryType)
{
// target.Type must be IRepository<"AnyEntity">
return repositoryType.GetGenericArguments().Single();
}
public static bool ImplementsInterface<TInterface>(Type type)
{
return typeof(TInterface).IsAssignableFrom(type);
}
}
I verified with a unit test that it works:
public class SomeSoftDeletableEntity : ISoftDeletable
{
}
[Fact]
public void RepositoryBinding()
{
var kernel = new StandardKernel();
kernel.Load<RepositoryModule>();
IRepository<SomeSoftDeletableEntity> repository = kernel.Get<IRepository<SomeSoftDeletableEntity>>();
repository.Should().BeOfType<SoftDeletableRepository<SomeSoftDeletableEntity>>();
}