Наследование ConstructorArguments в Ninject - PullRequest
2 голосов
/ 14 марта 2011

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

Проблема, с которой я столкнулся, заключается в том, что ConstructorArgument не наследуется дочерним экземплярам и следующие операторы не являются взаимозаменяемыми:

_parsingProcessor = _kernel.Get<IParsingProcessor>(new ConstructorArgument("dataFilePath", dataFilePath);

и

_parsingProcessor = _kernel.Get<IParsingProcessor>(new Parameter("dataFilePath", dataFilePath, true);

Итак, как получить наследуемый ConstructorArgument и когда имеет смысл, если вообще, иметь новый класс Parameter?

1 Ответ

3 голосов
/ 15 августа 2011

Да, вы можете сделать это, но это, вероятно, не то, что вы действительно хотите. Если контейнер фактически не отвечает за создание своих собственных зависимостей, то его зависимости , вероятно, не должны делиться аргументами своего конструктора - это просто не имеет смысла.

Я почти уверен, что знаю, что вы пытаетесь сделать, и рекомендуемый подход заключается в создании уникальной привязки специально для вашего одного контейнера и использовании синтаксиса условной привязки WhenInjectedInto, как в примере ниже:

public class Hello : IHello
{
    private readonly string name;

    public Hello(string name)
    {
        this.name = name;
    }

    public void SayHello()
    {
        Console.WriteLine("Hello, {0}!", name);
    }
}

Это класс, который принимает аргумент конструктора, который мы хотим изменить, в зависимости от того, кто запрашивает IHello. Допустим, это скучный контейнерный класс:

public class MyApp : IApp
{
    private readonly IHello hello;

    public MyApp(IHello hello)
    {
        this.hello = hello;
    }

    public virtual void Run()
    {
        hello.SayHello();
        Console.ReadLine();
    }
}

Теперь вот как вы делаете привязки:

public class MainModule : NinjectModule
{
    public override void Load()
    {
        Bind<IApp>().To<MyApp>();
        Bind<IHello>().To<Hello>()
            .WithConstructorArgument("name", "Jim");
        Bind<IHello>().To<Hello>()
            .WhenInjectedInto<MyApp>()
            .WithConstructorArgument("name", "Bob");
    }
}

В основном все, что делает эта привязка, говорит, что name должно быть "Jim" , если не запрашивается Hello, что в данном случае так, вместо этого он получит имя Боб».


Если вы абсолютно уверены , что действительно хотите каскадного поведения и понимаете, что это очень опасно и хрупко , вы можете обмануть, используя привязку метода. Предполагая, что теперь мы добавили аргумент name к классу MyApp для какой-то неопределенной цели, привязка будет:

Bind<IHello>().ToMethod(ctx =>
    ctx.Kernel.Get<Hello>(ctx.Request.ParentContext.Parameters
        .OfType<ConstructorArgument>()
        .Where(c => c.Name == "name")
        .First()));

Пожалуйста, пожалуйста, убедитесь, что вы положительный , что это то, что вы хотите, прежде чем делать это. Выглядит просто, но также очень вероятно, что он сломается во время простого рефакторинга, и 95% сценариев «настраиваемой зависимости», которые я видел, могут быть решены с помощью привязки WhenInjectedInto.

...