首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将INI文件解析为运行时属性

将INI文件解析为运行时属性
EN

Code Review用户
提问于 2014-12-01 15:12:25
回答 1查看 1.3K关注 0票数 4

目前,我正在开发一个应用程序,它使用了一些应该在.ini文件中更改的变量。由于我想让应用程序能够继续,如果用户“忘记”正确地实现变量(读:“防延迟”),我想我必须为每个变量创建一个对象,其中包含一个默认值和一个可选的设置值。我现在的实现方式是这样的;

IProperty.cs

代码语言:javascript
复制
public interface IProperty
{
    bool IsSet { get; set; }
    string PropertyName { get; set; }
    object GetValue();
}

Property.cs

代码语言:javascript
复制
public class Property<T> : IProperty
{
    public bool IsSet { get; set; }

    public Property()
    {
        IsSet = false;
    }

    public string PropertyName { get; set; }

    public T DefaultValue { get; set; }

    private T _CurrentValue;
    public T CurrentValue
    {
        get
        {
            return _CurrentValue;
        }
        set
        {
            IsSet = true;
            _CurrentValue = value;
        }
    }

    private T GetActualValue()
    {
        return IsSet ? CurrentValue : DefaultValue;
    }

    public object GetValue()
    {
        return (object)GetActualValue();
    }
}

PropertyFactory.cs

代码语言:javascript
复制
public static class PropertyFactory
{
    private static Dictionary<string, IProperty> CreateDefaults()
    {
        Dictionary<string, IProperty> dic = new Dictionary<string, IProperty>();
        List<IProperty> propList = new List<IProperty>();

        #region String properties
        propList.Add(new Property<string>(){ DefaultValue = @"C:\...\...", PropertyName = "log_path"});
        //...                      
        #endregion

        #region Int32 properties
        propList.Add(new Property<int>() { DefaultValue = 1337, PropertyName = "some_value"});         
        //...   
        #endregion

        #region Boolean properties
        propList.Add(new Property<bool>() { DefaultValue = false, PropertyName = "log_enabled" });
        //...
        #endregion

        //Map to the dictionary based on their name
        foreach(IProperty prop in propList)
        {
            dic.Add(prop.PropertyName, prop);
        }

        return dic;
    }

    public static ConcurrentDictionary<string, IProperty> CreateFromFile(string path)
    {
        Dictionary<string, IProperty> dic = CreateDefaults();
        INIFile ini = new INIFile(path);
        Dictionary<string, string> values = ini.GetAllValues();

        foreach(KeyValuePair<string, string> pair in values)
        {
            if (dic.ContainsKey(pair.Key))
            {
                if (dic[pair.Key] is Property<int>)
                {
                    int value;
                    if (!int.TryParse(pair.Value, out value)) continue;
                    ((Property<int>)dic[pair.Key]).CurrentValue = value;
                }

                if (dic[pair.Key] is Property<string>)
                {
                    ((Property<string>)dic[pair.Key]).CurrentValue = pair.Value;
                }

                if (dic[pair.Key] is Property<bool>)
                {
                    bool valueIsValid = (pair.Value == "true" || pair.Value == "false");
                    if (!valueIsValid) continue;
                    ((Property<bool>)dic[pair.Key]).CurrentValue = (pair.Value == "true");

                }
            }
        }
        ConcurrentDictionary<string, IProperty> cdic = new ConcurrentDictionary<string, IProperty>(dic);
        return cdic;
    }
}

INIFile.cs

代码语言:javascript
复制
public class INIFile
{
    private string _path;

    public INIFile(string path)
    {
        _path = path;
    }

    public Dictionary<string, string> GetAllValues()
    {
        string s;
        string name;
        string val;

        Dictionary<string, string> map = new Dictionary<string, string>();
        using(StreamReader sr = new StreamReader(_path)
        {
            while (!sr.EndOfStream)
            {
                while ((s = sr.ReadLine() ?? "").Contains("="))
                {
                    name = s.Split('=')[0];
                    val = s.Split('=')[1];
                    map.Add(name, val);
                }
            }
        }
        return map;
    }
}

最后,在实际项目中实施;

代码语言:javascript
复制
public static class Properties
{
    public static ConcurrentDictionary<string, IProperty> PropertyList = PropertyFactory.CreateFromFile(@"C:\...\...\settings.ini");
}

我对Property<T>的当前实现并不满意。它需要大量的拳击,这看起来很难看。例如;

代码语言:javascript
复制
if((bool)Properties.PropertyList["log_enabled"].GetValue()) //log...

但是,我想不出一个更好的实现来映射一个ConcurrentDictionary<>中的所有属性。有没有更好/更好的方法来做到这一点?另外,请注意,PropertyList必须由多个线程访问;因此我选择了ConcurrentDictionary<>

EN

回答 1

Code Review用户

发布于 2014-12-01 17:15:16

命名

名为ssr的变量对维护程序员没有帮助,他们更喜欢更长、更有解释性的名称。

我也倾向于声明我将要使用的变量(例如,在第一个while循环中的S),这样声明就不会离使用太远。

Var

当声明的右侧使类型变得明显时,在声明局部变量时使用var

例如:

代码语言:javascript
复制
Dictionary<string, string> map = new Dictionary<string, string>();

应该是

代码语言:javascript
复制
var map = new Dictionary<string, string>();

在声明循环变量时,还应该始终使用var

代码语言:javascript
复制
foreach(var pair in values)

线

像这样的台词:

代码语言:javascript
复制
propList.Add(new Property<string>(){ DefaultValue = @"C:\...\...", PropertyName = "log_path"});

可以通过在多条线上扩展,它可以简化可读性,并且不再需要滚动。

结果:

代码语言:javascript
复制
propList.Add(new Property<string>()
{ 
    DefaultValue = @"C:\...\...",
    PropertyName = "log_path"
});

区域

区域在方法之外是有争议的,但是每当我看到方法中的某个区域时,几乎可以肯定地保证该区域的内容应该被重构到它自己的方法中。您在原始代码中遗漏了一些行,因此这将是留给您的判断调用。

泛型

至于你的投诉:

代码语言:javascript
复制
if((bool)Properties.PropertyList["log_enabled"].GetValue()) //log...

GetValue()到底为什么会存在?

为什么不直接在界面中使用通用的GetActualValue()呢?

代码语言:javascript
复制
public interface IProperty
{
    bool IsSet { get; set; }
    string PropertyName { get; set; }
    T GetValue<T>();
}

然后调用GetValue<bool>()并让它返回一个布尔值,不需要装箱或取消装箱。

如果是错误的类型,则抛出异常,或者使用空值进行排序。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/71312

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档