房产注入被认为是不好的?

时间:2016-09-19 19:46:56

标签: c# .net ninject

演示问题的示例解决方案:

class World
{
    public override string ToString()
    {
        return "Hello World";
    }
}
class Hello
{
    [Inject]
    public World theWorld {  get;  set; }
    public Hello(IKernel kernel)
    {
        kernel.Inject(this);
    }
    public override string ToString()
    {
       return theWorld.ToString();
    }
}
class Program
{
    static IKernel kernel = new StandardKernel();
    static void RegisterServices()
    {
        kernel.Bind<World>().ToSelf();
    }
    static void Main(string[] args)
    {
        RegisterServices();
        Hello hello = new Hello(kernel);
        Console.WriteLine(hello.ToString());
        Console.ReadLine();
    }
}

这是我实际注册房产的方式。

如果符合以下条件,它将无法运作。

  1. 财产不公开(或其设定者)。
  2. 要求注入的类不会获取IKernel实例,而是调用kernel.Inject(this);
  3. 对我而言,这样做似乎非常过分和错误,只是为了获取属性的实例。是否有更简单的方法或我没有考虑过什么?

1 个答案:

答案 0 :(得分:8)

属性注入通常很糟糕,因为它会导致Temporal Coupling。属性注入应仅用于真正可选的依赖项(在您的情况下不是这样)。然而,依赖性几乎不应该是可选的。即使在没有依赖项实现的情况下,注入Null Object实现也比注入空引用更好。应通过构造函数注入所有必需的依赖项。

另一个不好的做法是让您的应用程序代码依赖于容器本身。这是一种称为Service Locator的反模式。您应该引用容器的唯一位置是Composition Root,即您所在的Program类。

相反,您的Hello类应该只接受World作为必需的构造函数参数:

class Hello
{
    private readonly World theWorld;

    public Hello(World theWorld) {
        if (theWorld == null) throw new ArgumentNullException("theWorld");
        this.theWorld = theWorld;
    }

    public override string ToString() {
        return theWorld.ToString();
    }
}

请注意我们如何从此类中完全删除对容器的任何引用。这使得类更简单,更易于维护,更易于测试,并且可以在不使用DI容器工具的情况下组成该类;通常称为Pure DI的做法。当您的应用程序很小时,Pure DI可能是比使用容器更好的选择。

以下是您的Program课程的样子:

class Program
{
    static void Main(string[] args)
    {
        // Configure
        var kernel = new StandardKernel();
        kernel.Bind<Hello>().ToSelf();
        kernel.Bind<World>().ToSelf();

        // Resolve
        var hello = kernel.Get<Hello>();

        // Use
        Console.WriteLine(hello.ToString());
        Console.ReadLine();
    }
}

没有容器,它将如下:

class Program
{
    static void Main(string[] args)
    {
        // Resolve
        var hello = new Hello(new World());

        // Use
        Console.WriteLine(hello.ToString());
        Console.ReadLine();
    }
}