Rai*_*baz 5 c# extension-methods
我有一个配置类,它从不同的源加载配置属性值,并允许以编程方式设置属性值。
目前,它尝试按以下顺序加载配置值:
由于大多数用户都以编程方式设置配置,并且我还想尽可能摆脱 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)
但我想知道是否有更好的方法来实现这一目标。
编辑澄清:我没有可用的依赖项容器,所以我不能使用依赖项注入,因为该类是库的一部分,我不想假设用户使用依赖项容器。
解决这个问题的一个好方法是使用.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接口可以公开具体的配置属性,并依赖于上面显示的抽象接口。