在运行时使用配置文件初始化对象

时间:2012-04-03 13:54:56

标签: c# .net .net-4.0 configuration-files

我目前正在编写一个需要根据XML配置文件生成不同类型对象的项目。

生成的每个对象都是IProvidor接口的实例,并且需要包含多个预处理和处理XML配置文件定义的方法。 我为:

生成了不同的工厂类
  1. 创建Provider(实现IProvider接口)
  2. 创建预处理操作(我有所有preProcessor类需要实现的IPreProcessor接口。
  3. 处理方法的相同之处(IHandler接口由多个类实现)。
  4. 问题

    如何在运行时将所有这些组合成一个对象?

3 个答案:

答案 0 :(得分:3)

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 Container配置它的示例。我正在使用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看起来像这样时,容器能够通过构造函数注入所需的依赖项(IHandlerIPreProcessor):

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

答案 1 :(得分:2)

我会创建一个包装器类来实现这些接口并注入功能。

示例接口

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);

答案 2 :(得分:0)

也许您可以像在运行时一样创建所有这些类的实例,然后将它们序列化为xml。然后,当您想要加载“配置”时,您只需要反序列化。

请参阅here了解序列化。