2015-10-21 4 views
1

Я использую Ninject v2.2.1.4, поэтому я не уверен, что так работают новые версии ninject.Ошибка множественных привязок для общего интерфейса

Я собираюсь использовать классический пример наследования, Animal. Поэтому у меня есть базовый аннотация Animal класс, а затем бесчисленные реализации Animal.

public abstract class Animal { } 
public class Tiger : Animal { } 

Теперь у меня есть IValidator для Animal, что удостоверяется свойства установлены правильно.

public interface IValidator<T> 
{ 
    bool Validate(T object); 
} 

Для каждой реализации Animal (Tiger, кошки, собаки, и т.д ..) Я может или не может иметь IValidator<T> реализации. Если для конкретного животного нет валидатора, я хочу использовать средство проверки по умолчанию, которое проверяет базовые свойства Animal (IValidator<Animal>).

Так вот пару реализаций IValidator<T>, включая реализацию по умолчанию:

// Contains default logic for base Animal inherited by all validators 
public abstract class AbstractAnimalValidator<TAnimal> : IValidator<TAnimal> where TAnimal : Animal { } 
// Default implementation for IValidator when the animal doesn't have a validator. 
//This just calls the base abstract validator logic. 
public DefaultAnimalValidator : AbstractAnimalValidator<Animal> { } 
// Validator for a Tiger. It calls the base validate method and then validates properties specific to a Tiger. 
public TigerValidator : AbstractAnimalValidator<Tiger> { } 

Давайте просто предположим, что тигр является единственным животным с его собственным валидатора. Я бы эти два привязок:

Bind<IValidator<Animal>>().To<DefaultAnimalValidator>(); 
Bind<IValidator<Tiger>>().To<TigerValidator>(); 

Так что теперь у меня будет логика, которая пытается внедрить валидатор для конкретного животного, пытаясь получить реализацию, таких как потребители инъекционных IValidator<Tiger>. Если он не существует, он вводит валидатор по умолчанию, используя IValidator<Animal>.

Проблема в том, что при попытке вставить IValidator<Tiger> обе указанные выше привязки совпадают, поэтому я обнаружил, что обнаружена множественная привязка. Это связано с тем, что Tiger наследует от Animal, поэтому Tiger является как Tiger, так и Animal. Я придумал некоторые хакерские решения по этому поводу, но есть ли что-то, что мне не хватает?

ответ

1

Можете изменить интерфейс IValidator<T>? Если да, то вы можете отметить параметр типа контрвариантным:

public interface IValidator<in T> 
{ 
    bool Validate(T o); 
} 

Это позволит вам, чтобы назначить IValidator<Animal> к IValidator<Tiger>. После этого вы можете указать все привязки в явном виде:

Bind<IValidator<Cat>>().To<DefaultAnimalValidator>(); 
Bind<IValidator<Dog>>().To<DefaultAnimalValidator>(); 
Bind<IValidator<Tiger>>().To<TigerValidator>(); 

Этот подход имеет также один большое преимущество над неявной Откат к IValidator<Animal>. Если вы добавите еще один класс, полученный из Animal, с его собственным валидатором и забудьте добавить привязку, вы получите ошибку во время выполнения. Если вы используете Bind<IValidator<Animal>>().To<DefaultAnimalValidator>(), вам будет сложно отслеживать ошибку.

+0

К сожалению, я не могу изменить интерфейс. Я использую библиотеку FluentValidation. Кроме того, это очень упрощенный пример. Мы явно не устанавливаем такие привязки. Мы используем генератор привязки и не хотим изменять логику в генераторе привязки. Я надеялся, что есть лучший способ структурировать это, чтобы я мог получить намеченную функциональность. –

+0

@wired_in Возможно, варианты [контекстного связывания Ninject] (https://github.com/ninject/Ninject/wiki/Contextual-Binding) могут помочь? –

Смежные вопросы