Почему я не могу ввести значение null с помощью Ninjects ConstructorArgument?

При использовании 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));
}

4 ответа

Решение

Глядя на источник (и трассировку стека, которую я получил повторением, которую вы пропустили: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 за этот совет / подталкивание!

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

Этот пост предоставляет дополнительную информацию.

Я хочу использовать его в своих юнит-тестах

Для модульных тестов нет необходимости использовать контейнер IOC. Вы должны использовать контейнер для соединения приложения во время выполнения, и ничего более. И если это начинает болеть, его запах указывает на то, что ваш класс выходит из-под контроля (нарушение SRP?)

Ваш тестовый модуль будет в этом примере:

var ninja = new Ninja(null);

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

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

Другие вопросы по тегам