Использование Dependency Injection во время выполнения после создания класса - PullRequest
0 голосов
/ 23 марта 2012

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

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

Когда пользователь выбирает, какие плагины он хочет использовать, создается экземпляр этого класса, чтобы он мог отображать доступные опции для этого плагина. Очевидно, что в нормальных условиях, когда классы являются экземплярами, передаются аргументы конструктора. В этом случае, если плагин имеет аргумент конструктора ILogger, а конкретный класс имеет аргумент конструктора DirectoryPath, но это доступно только для чтения, когда пользователь нажимает кнопку воспроизведения. мой контейнер МОК, чтобы передать это в?

public class MyPlugin
{ 
  private ILogger Logger;
  private Dictionary<string, object> Properties = new Dictionary<string, object>();

  public MyPlugin(ILogger Logger)
  {
     this.Logger = Logger;
     SetupProperties();
  }

  private SetupProperties()
  {
    Properties.Add("LogDirectory","Please enter a directory");
  }

  private void UserPressedPlay()
  {
     //We can now read the property values user has entered
     //Now I want to instantiate FileLogger with the LogDirectory property
  }

  public DoSomething(string Data)
  {
    this.Logger.Write(Data);
  }
}

public interface ILogger
{
  void Write(string Data);
}

public FileLogger : ILogger
{
  private string DirectoryPath;

  public FileLogger(string Directory)
  {
    this.DirectoryPath = Directory;
  }

  public Write(string Data)
  { 
      //Write to file
  }
}

Ответы [ 4 ]

0 голосов
/ 23 марта 2012

То, что вы хотите сделать, это пройти на фабрику ILogger, а не на настоящий ILogger. Затем фабрика может быть вызвана из UserPressedPlay с аргументами пользователя для создания фактического экземпляра Logger.

0 голосов
/ 23 марта 2012

Вы можете использовать Expression.New для динамического создания / вызова вашего конструктора с указанным параметром.

    Func<String, FileLogger> func = GetConsturctor<String, FileLogger>(); // Cache it somewhere.

    FileLogger logger = func(@"C:\Loggerpath\"); // instantiate

   static Func<TArg, TRes> GetConsturctor<TArg, TRes>()
    {
        Type resultType = typeof(TRes);
        Type argType = typeof(TArg);

        Type[] argumentArray = new Type[] { argType };
        ConstructorInfo constructor = resultType.GetConstructor(argumentArray);

        ParameterExpression param = Expression.Parameter(argType);
        Expression<Func<TArg, TRes>> result = Expression.Lambda<Func<TArg, TRes>>(
        Expression.New(constructor, param), param);
        return result.Compile();
    }
0 голосов
/ 23 марта 2012

Таким образом, DI обеспечивает большую гибкость и низкую связь, но это часто не требуется. В этом конкретном случае беспокоиться о том, как его добавить, может быть излишним. Похоже, у вас есть графический интерфейс, настроенный для соответствия классу FileLogger, который вы используете для его настройки, поэтому, возможно, DI здесь излишний. Есть ли у вас другие типы ILogger, которые ваш плагин использует сегодня? Если это так, заводской вариант потенциально может быть хорошим. Я подозреваю, однако, основываясь на упоминании графического интерфейса, что существует только один тип регистратора. В этом случае не зацикливайтесь на использовании DI здесь. Если вы пытаетесь понять, как тестировать класс MyPlugin, и не знаете, как это сделать без DI, дайте мне знать, и я расширю этот ответ, чтобы показать, как это сделать.

Надеюсь, это поможет!

Brandon

0 голосов
/ 23 марта 2012

Вы можете добавить свойство DirectoryPath к вашему FileLogger и инициализировать его позже.

public FileLogger : ILogger
{
    public string DirectoryPath { get; set; }

    public Write(string Data)
    {
        if (DirectoryPath != null) {
            // Write to file
        }
    } 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...