【问题标题】:Why can't I inject value null with Ninjects ConstructorArgument?为什么我不能用 Ninjects ConstructorArgument 注入 null 值?
【发布时间】:2011-02-09 16:02:07
【问题描述】:

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

【问题讨论】:

  • 我不熟悉ninject,但我认为问题在于IoC-container使用类型信息来找到合适的构造函数,并且无法通过空值找到它。您最好在文档或其代码中搜索答案。在我使用相应类型对象实例的一个库中,必须传递而不是 null。这里也可能有一些类似的解决方案。

标签: .net ioc-container ninject ninject-2 constructorargument


【解决方案1】:

查看源代码(以及我通过复制得到的堆栈跟踪,你省略了:P)

这是因为它绑定到 ConstructorArgument ctor 的重载,而不是正常用法(即,您传递值类型或非空引用类型)。

解决方法是将null转换为Object:-

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

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

上课?如果您不下载最新的源代码并查看它,您会发疯的。很棒的 cmets,干净的代码库。再次感谢 @Ian Davis 的提示/提示!

【讨论】:

  • 感谢您的解释。不要以为我想四处将空值转换为对象,但这似乎回答了我的问题!也许我得看看最新的消息来源:-)
  • @stiank81:正如我对@Finglas 答案的评论(我相信这是正确的答案,即使我同意这应该是 The Accepted One :P)说,它丑陋的原因是因为它不是打算在正常使用中完成(我们是否在另一个问题中介绍了 ConstructorArgument 是一种糟糕的默认方法?:P)@Finglas:谢谢,感谢您删除其他内容
【解决方案2】:

我不知道 Ninject,但是 AFAIK 构造函数注入通常用于强制依赖项,因此 null 在这种情况下没有什么意义。如果依赖项不是强制性的,则类型应提供默认构造函数并改用属性注入。

This post 提供更多信息。

【讨论】:

  • 我 +1d 是因为它似乎比 Gerrie 的回答更合乎逻辑。反思一下,我并不真正同意,因为它可以用于值类型以及引用类型,并且这一点在这种情况下并不能很好地概括。需要防范的是未指定的、随机未初始化的和/或未以明确的方式指定的依赖项,工具可以帮助您识别依赖链。
  • 属性注入是一个可接受的解决方案吗?如果是这样,这听起来很合理。谢谢链接。
  • @stiank81:虽然属性注入可能会完成您想要实现的基本目标(大量 null 值),但这样做会在代码清洁度方面失去很多,所以我会说不 - 我建议你参考@Finglas 的回答。
【解决方案3】:

我想在我的单元测试中使用它

no need to use an IOC container for unit tests。您应该使用容器在运行时将您的应用程序连接在一起,仅此而已。如果这开始受到伤害,那么它的气味表明您的班级正在失控(违反 SRP?)

您的单元测试将出现在此示例中:

var ninja = new Ninja(null);

以上是合法的 C# 代码,为单元测试传递一个空引用是不需要依赖的单元测试区域的一种完全有效的方法。

【讨论】:

  • +1 重要的一点,即使它没有回答问题(尽管这种情况可能是为什么这个问题(在null 的情况下解决错误的过载)没有被考虑一个问题。
  • @Ruben:没关系,除此之外,这就是 SO 的全部意义所在。改进和学习。
【解决方案4】:

这可能不受支持,因为构造函数参数也可以是值类型。

【讨论】:

  • 这促使我找到真正的答案,因为它感觉不对。但这也促使我反思不同意布赖恩的回答(我将两个 +0 都保留为但为时已晚,无法撤消另一个,虽然两者都提供了概念性见解,但我不相信它们代表 Ninject 试图鼓励/防止的任何事情/力)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 2016-05-15
  • 2021-10-27
  • 1970-01-01
  • 2018-07-25
相关资源
最近更新 更多