Предоставление Ninject с зависимостями конструктора, которые он не может разрешить? - PullRequest
1 голос
/ 22 декабря 2011

Отказ от ответственности : Я совершенно новичок в DI и IoC, пожалуйста, прости меня за любые серьезные недоразумения.

Рассмотрим ClassB, для которого требуется объект, реализующий IClassA. Ninject должен иметь возможность вставлять экземпляры ClassA в конструктор ClassB, предполагая, что он может создавать экземпляры ClassA:

public class ClassA : IClassA
{
    public ClassA(string runtimeDependency) { /* ... */ }
}

public class ClassB : IClassB
{
    public ClassB(IClassA depA) { /* ... */ }
}

public sealed class TestBootstrapModule : NinjectModule
{
    public override void Load()
    {
        Bind<IClassA>().To<ClassA>();
        Bind<IClassB>().To<ClassB>();
    }
} 

Теперь, допустим, некоторая логика времени выполнения используется для получения string runtimeDependency, предоставленного ClassA. Как мне предоставить Ninject runtimeDependency, чтобы он мог предоставить ClassB экземплярами ClassA?

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

Ответы [ 2 ]

2 голосов
/ 22 декабря 2011

Один способ сделать это - предоставить ClassA с помощью метода.Также имейте в виду, что с Ninject 2 вам не нужны модули, и вы можете выполнять привязки непосредственно в Ядре.

Bind<IClassA>().ToMethod(_ => 
  {
     // do something interesting with a runtimeDependancy
     return new ClassA(someInterestingVariable);
  });

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

0 голосов
/ 17 января 2017

Здесь есть несколько вариантов в зависимости от вашего дизайна и конкретной проблемы.Первое, самое простое решение - просто указать значение, когда вы запрашиваете сервис у Ninject

Kernel.Get<IClassA>("runtimeDependencyValue");

Если это невозможно, однако, все становится немного интереснее.Способ, который я решил ранее, заключается в создании контекстных привязок к самому System.String.

Скажем, если я хочу привязать строку подключения, я создам собственный атрибут:

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ConnectionStringAttribute : Attribute     
{
    /// <summary>
    /// Denotes the setting that you want to populate the given property with.
    /// </summary>
    public string SettingName { get; private set; }

    public ConnectionStringAttribute(string configSettingName = "")
    {
        SettingName = configSettingName;
    }
}

и затем я декорирую свой конструктор службы следующим образом:

public class ClassA : IClassA
{
    public ClassA([ConnectionString("AppDB")] string runtimeDependency) { /* ... */ }
}

Наконец, моя привязка будет выглядеть примерно так:

Bind<string>()
    .ToMethod(ctx => 
    {
        var attr = (ConnectionStringAttribute)context.Request.Target.GetCustomAttributes(typeof(ConnectionStringAttribute), true).First();
        string settingName = string.IsNullOrEmpty(attr.SettingName) ? context.Request.Target.Name : attr.SettingName;
        return ConfigurationManager.ConnectionStrings[settingName].ConnectionString;
    })
    .WhenTargetHas<ConnectionStringAttribute>();

Вы поняли идею.Надеюсь, это поможет:)

...