将魔法字符串替换为其他东西-具有层次结构支持

本文关键字:-具 层次结构 支持 其他 字符串 替换 | 更新日期: 2023-09-27 18:18:05

我想存储程序配置,我不想绑定任何实现(无论是XML还是ADO.NET)。配置本身在本质上是分层的。例如,它包含:

  • 数据库主机名
  • <
  • 数据库端口/gh>
  • 数据库用户
  • 打开/关闭X支持
  • 打开/关闭Y支持
  • Z
  • 参数

到目前为止,我已经创建了字符串到对象的字典,如:

var config = new Dictionary<string, string>();
config["database/host"] = "localhost";
config["database/port"] = "port";

然而,这是一件坏事,因为很难跟踪哪个模块使用了哪个键,而且很难重构。而且很明显它不是分层的

所以…我想用别的东西替换我的魔法字符串映射。我想知道解决方案:

  • 支持层次结构,所以很容易看到数据是如何结构的,
  • 不使用魔法字符串,
  • 尽量少用样板文件。

将魔法字符串替换为其他东西-具有层次结构支持

假设配置管理器是平面的,即它看起来像这样:

interface IConfigurationManager
{
    void Get(ConfigurationKey key);
    void Set(ConfigurationKey key, string value);
}
public class ConfigurationKey
{
    public ConfigurationKey(string name)
    {
        Name = name;
    }
    public string Name { get; private set; }
}

我想到了这个方法:

public static class ConfigurationKeys
{
    public static class Root
    {
        public static class Database
        {
            public static ConfigurationKey Host;
            public static ConfigurationKey Port;
            public static ConfigurationKey User;
        }
        public static class X
        {
            public static ConfigurationKey Enabled;
        }
        public static class Y
        {
            public static ConfigurationKey Enabled;
        }
    }
    public static void Build()
    {
        Build(typeof (ConfigurationKeys));
    }
    private static void Build(Type type)
    {
        var configurationKeyFields = type
            .GetFields()
            .Where(field => field.FieldType == typeof (ConfigurationKey));
        foreach (FieldInfo field in configurationKeyFields)
            field.SetValue(null, CreateConfigurationKey(type, field));
        var nestedClasses = type.GetNestedTypes().Where(nestedType => nestedType.IsClass);
        foreach (Type nestedClass in nestedClasses)
            Build(nestedClass.UnderlyingSystemType);
    }
    private static ConfigurationKey CreateConfigurationKey(Type type, FieldInfo field)
    {
        var parentPath = type.FullName.Substring(typeof (Root).FullName.Length + 1).Replace("+", "/");
        return new ConfigurationKey(parentPath + "/" + field.Name);
    }
}

现在很容易通过以下方式访问它:

ConfigurationKeys.Build();
var cm = new ConfigurationManager();
cm.Set(ConfigurationKeys.Root.Database.Host, "localhost");
ConfigurationKeys.Root.Database.Host // == "Database/Host"

优点:

  • 易于重构
  • 几乎没有样板
  • 嵌套,从而成功地描绘现实和智能感知友好

缺点:

  • 由于静态类和嵌套类型,几乎不可能在测试中模拟
  • 很难移植到其他语言,因为它依赖于反射的使用
  • Build()等方法的伪调用;不幸的是,它不能被静态构造函数取代,因为访问嵌套类型不会触发父静态构造函数,并且为每个嵌套类型提供静态构造函数会增加样板文件