Search code examples
.netioc-containerninjectninject-2constructorargument

Why can't I inject value null with Ninjects ConstructorArgument?


When using Ninjects ConstructorArgument you can specify the exact value to inject to specific parameters. Why can't this value be null, or how can I make it work? Maybe it's not something you'd like to do, but I want to use it in my unit tests.. Example:

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));
}

Solution

  • Looking at the source (and the stack trace I got by reproing which you omitted :P)

    This is because it's binding to a different overload of the ConstructorArgument ctor than the normal usage (i.e., where you're passing a Value Type or a non-null Reference Type) does.

    The workaround is to cast the null to Object:-

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

    Ninject 2 source:

    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) { }
    }
    

    Repro:

    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 ) );
        }
    }
    

    Lesson? You'd be crazy not to download the latest source and look at it. Great comments, nice clean codebase. Thanks again to @Ian Davis for that tip/prodding!