Инициализация объектов с использованием файла конфигурации во время выполнения - PullRequest
0 голосов
/ 03 апреля 2012

В настоящее время я пишу проект, который должен генерировать другой тип объекта на основе файла конфигурации XML.

Каждый сгенерированный объект является экземпляром интерфейса IProvidor и должен содержать несколько методов предварительной обработки и обработки, определенных в файле конфигурации XML. Я создал разные классы фабрик для:

  1. создание провайдера (реализующего интерфейс IProvider)
  2. создание операции предварительной обработки (у меня есть интерфейс IPreProcessor, который необходимо реализовать всем классом препроцессора.
  3. то же самое для обработки методов (интерфейс IHandler реализуется несколькими классами).

Вопрос

Как я могу объединить все это в один объект во время выполнения?

Ответы [ 3 ]

3 голосов
/ 03 апреля 2012

Olivier Jacot-Desc абсолютно на верном пути (+1 за это).Единственное, чего не хватает в его ответе, - это загрузить правильные реализации из конфигурации.

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

IProvider providerX = GetProviderFromConfig();
IHandler handlerZ = GetHandlerFromConfig();
IPreProcessor preProcessorY = GetProcessorFromConfig();

var provider = 
    new ProviderWrapper(providerX, preProcessorY, handlerZ);

private static IProvider GetProviderFromConfig()
{
    if (ConfigurationManager.AppSettings["provider"] == "mail")
    {
         return new MailProvider();
    }
    else
    {
         return new FtpProvider();
    }
}

// implement GetHandlerFromConfig  just like
// the GetProvider.

ОБНОВЛЕНИЕ

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

private static IProvider GetProviderFromConfig()
{
    string typeName =
        ConfigurationManager.AppSettings["provider"];

    Type providerType = Type.GetType(typeName);

    return (IProvider)
        Activator.CreateInstance(providerType);
}

ОБНОВЛЕНИЕ 2

Вот пример того, как настроить это с Контейнером DI.Я использую Simple Injector extensions ), но подойдет любой контейнер (хотя способ его настройки будет отличаться для каждого контейнера):

Регистрация:

using SimpleInjector;
using SimpleInjector.Extensions;

Type providerType = Type.GetType(
    ConfigurationManager.AppSettings["provider"]);

Type handlerType = Type.GetType(
    ConfigurationManager.AppSettings["handler"]);

Type processorType = Type.GetType(
    ConfigurationManager.AppSettings["preProcessor"]);

var container = new Container();

container.Register(typeof(IProvider), providerType);
container.Register(typeof(IHandler), handlerType);
container.Register(typeof(IPreProcessor), processorType);

Разрешение поставщика:

var provider = container.GetInstance<IPovider>();

Совет. Если вы используете инжектор конструктора, вам не нужно связывать типы вручную, контейнер сделает это за вас.Например, когда ваш MailProvider выглядит следующим образом, контейнер может внедрить необходимые зависимости (IHandler и IPreProcessor) через конструктор:

public class MailProvider : IProvider
{
    private readonly IHandler handler;
    private readonly IPreProcessor preProcessor;

    public MailProvider(IHandler handler, 
        IPreProcessor preProcessor)
    {
        this.handler = handler;
        this.preProcessor = preProcessor;
    }

    public void SomeAction() { ... }
}
2 голосов
/ 03 апреля 2012

Я бы создал класс-оболочку, который реализует эти интерфейсы и внедряет функциональность.

Примеры интерфейсов

public interface IProvider
{
    string ProvideSomething(int id);
}

public interface IPreProcessor
{
    void PreProcess(string parameter);
}

public interface IHandler
{
    void HandleSomething();
}

Оболочка будет реализовывать все эти интерфейсы

public class ProviderWrapper : IProvider, IPreProcessor, IHandler
{
    private IProvider _provider;
    private IPreProcessor _preProcessor;
    private IHandler _handler;

    public ProviderWrapper(IProvider provider, IPreProcessor preProcessor, IHandler handler)
    {
        _provider = provider;
        _preProcessor = preProcessor;
        _handler = handler;
    }

    #region IProvider Members

    public string ProvideSomething(int id)
    {
        return _provider.ProvideSomething(id);
    }

    #endregion

    #region IPreProcessor Members

    public void PreProcess(string parameter)
    {
        _preProcessor.PreProcess(parameter);
    }

    #endregion

    #region IHandler Members

    public void HandleSomething()
    {
        _handler.HandleSomething();
    }

    #endregion
}

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

var provider = new ProviderWrapper(providerX, preProcessorY, handlerZ);
0 голосов
/ 03 апреля 2012

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

См. здесь для сериализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...