2

The code I have is...

public interface IEntityA : IGenericEntity { ... }
public interface IEntityB : IGenericEntity { ... }
....
public interface IEntityZ : IGenericEntity { ... }

public class EntityComparer<T> : IEqualityComparer<T> where T : IGenericEntity
{
...
}

public class ZComparer : EntityComparer<IEntityZ>
{
... some overrides
} 

Bindings...

Bind(typeof(IEqualityComparer<>)).To(typeof(EntityComparer<>));
Bind<IEqualityComparer<IEntityZ>>().To<ZComparer>();

This works ! So when you then ask for instances like so...

var aComparer = Kernel.Get<IEqualityComparer<IEntityA>>(); 
// gives you an instance of EntityComparer<IEntityA>>
var bComparer = Kernel.Get<IEqualityComparer<IEntityB>>(); 
// gives you an instance of EntityComparer<IEntityB>>
var zComparer = Kernel.Get<IEqualityComparer<IEntityZ>>(); 
// gives you an instance of ZComparer

However I want to assure these bindings only affect entities. If I change the bindings to...

Bind(typeof(IEqualityComparer<>)).To(typeof(EntityComparer<>))
 .When(r => typeof(IGenericEntity).IsAssignableFrom(r.Service.GetGenericArguments()[0]));
Bind<IEqualityComparer<IEntityZ>>().To<ZComparer>();

There is a problem with bindings for specific entities...

var zComparer = Kernel.Get<IEqualityComparer<IEntityZ>>(); 
// gives you an instance of EntityComparer<IEntityZ>>  - undesired !

What's the best way to do this?

Mick
  • 6,527
  • 4
  • 52
  • 67
  • 2
    What do you mean on "However I want to assure these bindings only affect entities."? Because of the `where T : IGenericEntity` on the EntityComparer` you cannot have a `EntityComparer` where `INotEntity` is not an `IGenericEntity`. So this Get call will fail and throw an exceptio: `Kernel.Get>(); ` – nemesv Aug 12 '14 at 07:06
  • Good point ! So if you bind IEqualityComparer for some other type you're saying NInject is smart enough not to try and use the EntityComparer and to use the other binding instead. I'd still like to understand why the ".When" constraint on the second set of bindings has the effect it does. As you've pointed out it should be superfluous, however it causes NInject to instantiate the wrong class for IEntityZ – Mick Aug 12 '14 at 07:20
  • 1
    In general it is superfluous because in both cases Ninject will throw an exception although a different one: in the first case you get an argument exception and in the second case you get a binding is not found exception.About the `When`: it changes the order of the registration of the bindings so your `Bind>().To();` does not overrides the generic one.One way to fix this (although I'm not sure that this is the proper one so I'm not adding this as an answer) to add an empty when:`Kernel.Bind>().To().When(r => true)` – nemesv Aug 12 '14 at 07:30
  • Thanks ! I was thinking the ".When" might be necessary if at a later stage someone attempted to create binding for another implementation of IEqualityComparer that is not related to IGenericEntity. – Mick Aug 12 '14 at 07:35
  • 2
    YAGNI. Don't do things just because you might need it later. If you would, it *might* be better to define an `IEntityComparer : IEqualityComparer where TEntity : IEntity` interface anyways. But this will only be known when you'll need it. – BatteryBackupUnit Aug 12 '14 at 15:53
  • 1
    That's one way of looking at it. In a large project sometimes sweeping code like Bind(typeof(IEqualityComparer<>)).To(typeof(EntityComparer<>)), that takes a generic interface and binds it to a far less generic class, can end up getting someone else in trouble. Creating an IEntityComparer interface is a good alternative. – Mick Aug 13 '14 at 00:33
  • @nemesv care to write this down as an answer so it won't get deleted from SO eventually? – BatteryBackupUnit Aug 13 '14 at 06:24
  • @Mick i agree. Best case would be if you could create automated tests that detect such regressions. Sadly enough these kind of tests often don't compose the "composition root" the same way as the actual product, rendering the tests less useful. That's one of the things i'm still looking for "the perfect approach". – BatteryBackupUnit Aug 13 '14 at 06:33

0 Answers0