涉及属性中类型的库中DI的最佳实践



我正在开发一个简化应用程序配置的库。从本质上讲,库的使用者要么用属性装饰他们的配置类,要么在代码中声明性地初始化设置。可以指定一个或多个源,从中读取/写入配置属性(访问器)或从类继承默认值。例如,以下内容:

[ConfigurationNamespace(DefaultAccessors = new Type[] { typeof(AppSettingsAccessor) })]
public class ClientConfiguration : Configuration<IClientConfiguration>
{
    [ConfigurationItem(Accessors = new Type[] { 
        typeof((RegistryAccessor)) 
     })]
    public bool BypassCertificateVerification { get; set; }
}

将相当于

var config = new Configuration<IClientConfiguration>();
config.SetDefaultAccessors(new[] { typeof(AppSettingsAccessor) });
config.SetPropertyAccessors(
    property: x => x.BypassCertificateVerification,
    accessors: new[] { typeof(RegistryAccessor) }
);

访问者处理阅读&从各种来源(AppSettings、registry、.ini等)编写。我希望允许消费者扩展功能以满足他们的需求。我想让它与IoC容器无关。之所以给我Type[]约束,是因为由于编译时与运行时的问题,我无法在属性中指定类型。

是否有一种方法可以使用默认机制来实例化这些访问者(例如,基于Activator.CreateInstance的东西),但也允许使用代码在运行时实例化这些访问者,而无需使用服务定位器/依赖解析程序模式?我读了很多关于为什么服务定位器/依赖解析程序模式是一个邪恶的反模式的文章,但我想不出更好的工具来完成这项工作。我看到MVC框架和SignalR库使用依赖解析程序。他们100%都是邪恶的,还是这是一个边缘案件?据我所知,抽象工厂模式不会切割它,因为它不喜欢Type参数。

在这种特殊情况下,基于属性的配置将比声明性方法更有用,所以我不想放弃我的配置属性(这将允许我将Type更改为IConfigurationAccessor并切换到工厂方法)。

通过DSL的工作,我们知道将API从其他表达模式中分离到底层的语义模型是很重要的。在这种情况下,Configuration<T> API在我看来就像是语义模型。没有理由在基于属性的DSL之后对语义模型进行建模。这样的东西对我来说更有意义:

var config = new Configuration<IClientConfiguration>();
config.DefaultAccessors.Add(new AppSettingsAccessor());
config.PropertyAccessorsFor(x => x.BypassCertificateVerification)
    .Add(new RegistryAccessor());

我还将基于属性的模型更改为纯粹的声明性模型:

[AppSettingsConfiguration]
public class ClientConfiguration : Configuration<IClientConfiguration>
{
    [RegistryConfiguration]
    public bool BypassCertificateVerification { get; set; }
}

现在,您"只"需要找到一种从自适应模型转换为语义模型的方法。

这基本上与任何其他Serialization读取器一样:读取数据,并从类型注释中获得如何读取数据的提示。这基本上是对数据结构的递归遍历,对于每个节点,您都需要创建一个访问器。

假设所有访问器都实现了一个类似IAccessor的接口,则可以使用抽象工厂:进行扩展

public interface IAccessorFactory
{
    IAccessor CreateAccessor(ConfigurationAttribute configurationAttribute);
}

实际上,更具体地说,这是PLoPD4中描述的一种不太为人所知的设计模式,称为ProductTrader,但由于大多数人不知道这种模式,我们只将其称为抽象工厂-它不是服务定位器,因为它不返回无界类型-它只返回IAccessor实例。

最新更新