Ninject.可选注射

And*_*doi 19 c# ninject

我有启用/禁用功能的全局标志.我想根据一些标志注入一些依赖项.某些功能需要构造较多的类,因此如果标志的值为false,则我想注入null,否则需要实际的依赖项.Ninject不允许注入null.还有其他选择吗?

更新:构造函数参数可以使用OptionalAttribute属性进行修饰.在这种情况下,如果没有找到相应的绑定,则注入null.这里有一个问题:我无法验证目标类是否可以正确构造.我对每个公共依赖项进行了测试,验证它是否可以成功构建.如果标志的值为true,我将无法在使用该OptionalAttribute属性修饰的依赖项时找到错误,无法正确构造.我只想在绑定级别上管理它.

Tim*_*oyd 17

您可以通过使用工厂方法(即ToMethod)进行绑定来改变注入行为,并且可以通过配置容器的AllowNullInjection设置来允许注入空值.

另一种选择是使用工厂方法并提供轻量级虚拟对象而不是重量级类.如果您正在使用接口,这将是直截了当的,只是让接口的实现什么都不做.你甚至可以使用像FakeItEasy这样的模拟框架为你构建这些假人.这里的好处是,虚拟使特殊行为对客户端透明,即客户端不需要检查null等.

使用工厂方法的示例,加上AllowNullInjection和null:

public void Configure()
{
    bool create = true;

    IKernel kernel = new StandardKernel();

    kernel.Settings.AllowNullInjection = true;

    kernel.Bind<IFoo>().ToMethod(ctx => create ? ctx.Kernel.Get<Foo>() : null);

    DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>();
}

private interface IFoo {}

private class Foo : IFoo {}

private class DependendsOnIFoo
{
    public DependendsOnIFoo(IFoo foo) {}
}
Run Code Online (Sandbox Code Playgroud)

并根据标志替换轻量级对象的示例:

public void Configure()
{
    bool heavy = true;

    IKernel kernel = new StandardKernel();

    kernel.Bind<IFoo>()
     .ToMethod(ctx => heavy ? ctx.Kernel.Get<HeavyFoo>() : (IFoo)new DummyFoo());

    DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>();
}

private interface IFoo {}

private class HeavyFoo : IFoo {}

private class DummyFoo : IFoo { }

private class DependendsOnIFoo
{
    public DependendsOnIFoo(IFoo foo) {}
} 
Run Code Online (Sandbox Code Playgroud)


Rem*_*oor 12

注入null通常不是一个明智的想法.如果对象为null,则会检查您的代码是否为null,如下面的代码所示:

public interface IFoo
{
    void Do();
}

public class Foo : IFoo
{
    public void Do()
    {
       DoSomething();
    }
}

public class UglyNullCheckingBar
{
    IFoo foo;
    public Bar(IFoo foo)
    {
        this.foo = foo;
    }

    public void Do()
    {
        if (this.foo != null)
        {
            this.foo.Do();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下更好的方法是实现一个Null对象,它绝对没有任何东西,并注入这个而不是null.这样可以保持代码清洁.

public class NullFoo : IFoo
{
    public void Do() {}
}

public class Bar
{
    IFoo foo;
    public Bar(IFoo foo)
    {
        this.foo = foo;
    }

    public void Do()
    {
        this.foo.Do();
    }
}
Run Code Online (Sandbox Code Playgroud)