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

本文关键字:初始化 对象 配置文件 运行时 | 更新日期: 2023-09-27 18:30:03

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

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

  1. 创建提供程序(实现IProvider接口)
  2. 创建预处理操作(我有所有preProcessor类都需要实现的IPreProcessor接口
  3. 处理方法也是如此(IHandler接口由几个类实现)

问题

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

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

Olivier Jacobt 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(带扩展),但任何容器都可以(尽管每个容器的配置方式不同):

注册:

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

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

接口示例

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

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

有关序列化,请参见此处。