在不同的程序集中重新实现类方法

Rai*_*baz 5 c# extension-methods

我有一个配置类,它从不同的源加载配置属性值,并允许以编程方式设置属性值。

目前,它尝试按以下顺序加载配置值:

  • 环境变量
  • 应用程序配置文件
  • 设置.json 文件
  • 使用默认值并允许用户在自己的代码中更改属性

由于大多数用户都以编程方式设置配置,并且我还想尽可能摆脱 Microsoft.Extensions.Configuration 依赖项,因此我想将前三种情况移动到不同的程序集中,以便在用户想要时明确依赖例如,从 App.config 文件加载配置属性。

理想情况下,我希望更改对用户来说是透明的,这样他们就不必更改现有的代码。

我的配置类目前在其构造函数中所做的事情是:

public Config()
{
    InitializeDefaults();
    ReadEnvironmentVariables();
    ReadAppConfig();
}
Run Code Online (Sandbox Code Playgroud)

有没有办法在我现有的程序集中提供ReadEnvironmentVariables和的空实现ReadAppConfig,并将其替换为新程序集中的实际实现,这样,如果应用程序的依赖项中有新程序集,则它使用实际的实现,否则默认为空方法?

我可以通过在新程序集中#defining一个常量并执行以下操作来做到这一点

#if CONFIG_EXTENSION
    ReadEnvironmentVariables();
    ReadAppConfig();
#endif
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有更好的方法来实现这一目标。

编辑澄清:我没有可用的依赖项容器,所以我不能使用依赖项注入,因为该类是库的一部分,我不想假设用户使用依赖项容器。

Oli*_*bes 2

解决这个问题的一个好方法是使用.NET依赖注入。基本上,您不是针对类进行编程,而是针对接口进行编程,并在类中注入实现。

public interface IConfigFactory
{
    IConfig GetConfiguration();
}

public interface IConfig
{
    bool TryGetValue<T>(string key, out T value);
}
Run Code Online (Sandbox Code Playgroud)

IConfigFactory.GetConfiguration()然后负责仅在第一次调用时加载配置,并在后续调用时返回相同的实例。您还可以添加一个Reset()方法,强制在下次调用时重新加载新版本的配置。

然后在你的一堂课中你像这样注入它

public class ExamplePrintService
{
    private readonly IConfig _config;

    public ExamplePrintService (IConfigFactory configFactory)
    {
        _config = configFactory.GetConfiguration();
    }

    public void Print(IDocument doc)
    {
        double leftMargin = _config.TryGetValue<double>("leftmargin", out var lm)
            ? lm
            : 9.0;
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用 IoC 容器,则可以将其实现注册为IConfigFactory单例。在应用程序启动时,您可以选择注册不同的实现。应用程序的其余部分不需要关心使用哪个实现或如何检索配置。

正如 @Ralf 指出的,您可以在没有 IoC 容器的情况下使用此模式。IoC 容器可以在中心位置进行配置,然后自动注入依赖项。如果没有它,您将必须手动注入依赖项。

您还可以有不同级别的抽象。例如,IPrintConfig接口可以公开具体的配置属性,并依赖于上面显示的抽象接口。