2010-04-19 2 views
5

При использовании Ninjects ConstructorArgument вы можете указать точное значение для ввода определенных параметров. Почему это значение не может быть нулевым или как я могу заставить его работать? Может быть, это не то, что вы хотели бы сделать, но я хочу, чтобы использовать его в своих модульных тестов .. Пример:Почему я не могу ввести значение null с помощью Ninjects ConstructorArgument?

public class Ninja 
{ 
    private readonly IWeapon _weapon; 
    public Ninja(IWeapon weapon) 
    { 
     _weapon = weapon; 
    } 
} 

public void SomeFunction() 
{ 
    var kernel = new StandardKernel(); 
    var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", null)); 
} 
+0

Я не знаком с ninject, но я думаю, что проблема в том, что IoC-container использует информацию о типе, чтобы найти подходящий конструктор, и он не может найти его по нулевому значению. Лучше искать ответ в документации или в его коде. В одной библиотеке, которую я использовал экземпляр соответствующего объекта типа, нужно передать вместо null. Здесь может быть и такое же решение. – SergGr

+0

Спасибо, сэр :-) – stiank81

ответ

7

Глядя на источник (и трассировки стека я получил от reproing который вы пропущенной: P)

Это происходит потому, что это связывание с другой перегрузки ConstructorArgument CTOR, чем нормального использования (то есть, где вы» повторная передача типа значения или непустого ссылочного типа).

Чтобы обойти эту проблему, чтобы бросить пустой указатель на объект: -

var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", (object)null)); 

Ninject 2 Источник:

public class ConstructorArgument : Parameter 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="ConstructorArgument"/> class. 
    /// </summary> 
    /// <param name="name">The name of the argument to override.</param> 
    /// <param name="value">The value to inject into the property.</param> 
    public ConstructorArgument(string name, object value) : base(name, value, false) { } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="ConstructorArgument"/> class. 
    /// </summary> 
    /// <param name="name">The name of the argument to override.</param> 
    /// <param name="valueCallback">The callback to invoke to get the value that should be injected.</param> 
    public ConstructorArgument(string name, Func<IContext, object> valueCallback) : base(name, valueCallback, false) { } 
} 

Репро:

public class ReproAndResolution 
{ 
    public interface IWeapon 
    { 
    } 

    public class Ninja 
    { 
     private readonly IWeapon _weapon; 
     public Ninja(IWeapon weapon) 
     { 
      _weapon = weapon; 
     } 
    } 

    [Fact] 
    public void TestMethod() 
    { 
     var kernel = new StandardKernel(); 
     var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", (object)null)); 
    } 
} 

Урок? Вы были бы сумасшедшими, чтобы не загружать последний источник и не смотреть на него. Отличные комментарии, хорошая чистая кодовая база. Еще раз спасибо @Ian Davis за подсказку/подталкивание!

+0

+1 Ницца - интересный материал. – Finglas

+0

Thx для объяснения. Не думайте, что я хочу обойти ноль для объектов, но это, похоже, отвечает на мой вопрос! Возможно, я должен проверить последний источник :-) – stiank81

+0

@ stiank81: Как мой комментарий к ответу @Finglas (который, я считаю, правильный ответ, даже если я согласен, что это должен быть принятый: P) говорит, что причина уродливая потому что его не предназначено для нормального использования (разве мы не рассматриваем конструкторArgument как плохой подход по умолчанию в другом вопросе?: P) @Finglas: Спасибо, спасибо за удаление других вещей –

0

Это, вероятно, не поддерживается, потому что аргументы конструктора могут быть типы значений тоже.

+0

Это побудило меня найти реальный ответ, поскольку он чувствовал себя не так. Но это также побудило меня размышлять, чтобы не согласиться с ответом Брайана (я бы оставил оба +0, но слишком поздно, чтобы отменить другой, и хотя оба предоставили концептуальную проницательность, я не верю, что они представляют что-то, что Ninject пытается поощрить/force) –

3

Я не знаю Ninject, но инъекция конструктора AFAIK обычно используется для обязательных зависимостей, и, таким образом, null имеет мало смысла в этом контексте. Если зависимость не является обязательной, тип должен предоставлять конструктор по умолчанию и вместо этого использовать инъекцию свойств.

This post содержит дополнительную информацию.

+0

I + 1d это потому, что это казалось более логичным, чем ответ Джерри.При отражении я действительно не согласен, так как его можно использовать для типов значений, а также для ссылочных типов, и точка в этом контексте не очень хорошо обобщается. То, что нужно защитить, - это неопределенные, случайные неинициализированные и/или зависимости, которые не указаны четким образом, что инструменты могут помочь вам идентифицировать сети зависимостей. –

+0

Впрыск продукта является приемлемым решением для этого? Если так, то это звучит как разумная вещь. Thx для ссылки. – stiank81

+0

@ stiank81: В то время как вложение свойств может выполнить основную задачу, которую вы пытаетесь достичь (множество значений «null»), при этом вы сильно потеряете много в Чистоте кода, поэтому я бы сказал, что нет - я обратитесь к ответу @Finglas. –

3

Я хочу, чтобы использовать его в моем блоке тестов

Существует no need to use an IOC container for unit tests. Вы должны использовать контейнер, чтобы связать ваше приложение во время выполнения, и ничего больше. А если начинает болеть, его запах указывает на ваш класс получает из рук

Ваш аппарат тест будет в этом примере (SRP нарушение?):

var ninja = new Ninja(null); 

выше законен C# код , и передача нулевой ссылки для модульного тестирования является вполне допустимым способом областей тестирования модулей, которые не нуждаются в зависимости.

+0

+1 Важный вопрос, даже если он не отвечает вопрос (хотя тот факт, что это так, вероятно, потому, что эта проблема (разрешение неправильной перегрузки в случае «null») не считается проблемой. –

+0

@Ruben: Это прекрасно, кроме того, это то, Улучшение и обучение. – Finglas