Ninject.Дополнительный впрыск - PullRequest
19 голосов
/ 01 июля 2011

У меня есть глобальные флаги, которые включают / отключают функции.Я хотел бы добавить некоторые зависимости в зависимости от флага.Для некоторых функций требуются классы, которые в значительной степени построены, поэтому я хочу ввести null, если значение флага равно false, а фактическая зависимость - в противном случае.Ninject не позволяет вводить ноль.Есть ли другие варианты?

Обновление: аргументы конструктора могут быть украшены атрибутом OptionalAttribute.В этом случае null вводится, если соответствующая привязка не найдена.Здесь есть проблема: я не могу проверить, может ли целевой класс быть правильно сконструирован.У меня есть тест для каждой публичной зависимости, которая проверяет, может ли она быть успешно построена.В случае, если значение флага истинно, я не смогу найти ошибку, когда зависимость, украшенная атрибутом OptionalAttribute, не может быть построена должным образом.Я хотел бы управлять им только на уровне привязки.

Ответы [ 2 ]

17 голосов
/ 01 июля 2011

Вы можете изменить поведение внедрения путем привязки, используя фабричный метод (т. Е. ToMethod), и можно разрешить введение нулей, настроив параметр контейнера AllowNullInjection.

Другой альтернативой может быть использование фабричного метода и предоставление легкого фиктивного объекта вместо вашего тяжелого класса. Если вы используете интерфейсы, это было бы просто, просто есть реализации интерфейса, которые ничего не делают. Вы могли бы даже использовать фальшивый фреймворк, такой как FakeItEasy, для создания этих манекенов для вас. Преимущество в том, что манекен делает специальное поведение прозрачным для клиентов, т. Е. Клиентам не нужно проверять null и т. Д.

Пример использования фабричного метода, плюс AllowNullInjection и нули:

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

И пример, где легкий объект заменяется в зависимости от флага:

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) {}
} 
12 голосов
/ 01 июля 2011

Внедрение 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();
        }
    }
}

Лучший способ в этом случае - реализовать нулевой объект, который абсолютно ничего не делает, и внедрить этотвместо нуля.Это сохраняет ваш код в чистоте.

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