我可以使用具有强命名的Ninject ConstructorArguments吗?

时间:2010-04-14 11:21:50

标签: .net refactoring naming ninject constructorargument

好吧,我不知道“强命名”是否是正确的术语,但我想做的是如下。

目前我使用ConstructorArgument,例如这个:

public class Ninja
{
    private readonly IWeapon _weapon;
    private readonly string _name;

    public Ninja(string name, IWeapon weapon)
    {
        _weapon = weapon;
        _name = name;
    }
    // ..more code..
}

public void SomeFunction()
{
    var kernel = new StandardKernel();
    kernel.Bind<IWeapon>().To<Sword>();
    var ninja = kernel.Get<Ninja>(new ConstructorArgument("name", "Lee"));
}

现在,如果我重命名参数“name”(例如使用ReSharper),ConstructorArgument将不会更新,并且在创建Ninja时我将收到运行时错误。要解决这个问题,我需要手动查找我通过ConstructorArgument指定此参数的所有位置并更新它。没有好处,即使我有良好的测试覆盖率,我注定会在某些时候失败。重命名应该是一个廉价的操作。

有没有办法可以引用参数 - 这样当我重命名参数时它会被更新?

3 个答案:

答案 0 :(得分:5)

如果您可以分享更多您真正想要实现的目标,那么您将获得更好的答案。一般来说,你根本不想依赖于传递一个ConstructorArgument,如果可以帮助的话 - 它应该是将参数值用于创建你不拥有的组件的最后手段,因此可以依赖于在重构活动期间被重新命名为willy nilly。因此对于普通代码,如果你可以尝试将它保留在接口上以使事情明确无误并且不依赖于更好的名称。

现在不能挖掘出一个例子,但有一个非常常见的成语static reflection。提供的ConstructorArgument可以在任何构造函数中匹配该名称的任何参数,因此静态反射在这个实例中不是最恰当的。

因此,最好的静态反射可能会让你实现类似的东西:

var ninja = ninject.Get<Ninja>( ParamNamesOf(()=>new Ninja( "dummy", "dummy" )).First() );

您将看到的典型示例是,您想要提取实例上正在访问的属性的名称。这有点不同,因为它需要处理构造函数调用表达式。

至于找到一个已经有这个的合适的lib,为搜索者练习:D(但是我建议找一个更好的方式来表达你想要做的事情,而不是使用ConstructorArgument而不是这个无论如何。)

答案 1 :(得分:4)

正如您已经注意到的,这种方法非常脆弱,应该避免。尝试一个设计,你不需要添加名称作为构造函数参数。你可以这样做:

public class Ninja
{
    private readonly IWeapon _weapon;

    public Ninja(IWeapon weapon)
    {
        _weapon = weapon;
    }

    public string Name { get; set; }

    // ..more code..
}

public void SomeFunction()
{
    var kernel = new StandardKernel();
    kernel.Bind<IWeapon>().To<Sword>();
    var ninja = ninject.Get<Ninja>();
    ninja.Name = "Lee";
}

我希望这会有所帮助。

答案 2 :(得分:0)

是的,你可以。

我已经实现了这个:

    public string GiveConstuctorArgumentName(Type class, Type constructorArgument)
    {
       var cons = class.GetConstructors();

       foreach (var constructorInfo in cons)
       {
          foreach (var consParameter in constructorInfo.GetParameters())
          {
             if (consParameter.ParameterType == constructorArgument)
             {
                return consParameter.Name;
             }
          }
       }

       throw new InstanceNotFoundException();
    }

它没有LINQ,但它是了解其工作原理的良好开端。