目前,我正在开发一个应用程序,它使用了一些应该在.ini文件中更改的变量。由于我想让应用程序能够继续,如果用户“忘记”正确地实现变量(读:“防延迟”),我想我必须为每个变量创建一个对象,其中包含一个默认值和一个可选的设置值。我现在的实现方式是这样的;
public interface IProperty
{
bool IsSet { get; set; }
string PropertyName { get; set; }
object GetValue();
}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();
}
}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;
}
}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;
}
}最后,在实际项目中实施;
public static class Properties
{
public static ConcurrentDictionary<string, IProperty> PropertyList = PropertyFactory.CreateFromFile(@"C:\...\...\settings.ini");
}我对Property<T>的当前实现并不满意。它需要大量的拳击,这看起来很难看。例如;
if((bool)Properties.PropertyList["log_enabled"].GetValue()) //log...但是,我想不出一个更好的实现来映射一个ConcurrentDictionary<>中的所有属性。有没有更好/更好的方法来做到这一点?另外,请注意,PropertyList必须由多个线程访问;因此我选择了ConcurrentDictionary<>。
发布于 2014-12-01 17:15:16
名为s和sr的变量对维护程序员没有帮助,他们更喜欢更长、更有解释性的名称。
我也倾向于声明我将要使用的变量(例如,在第一个while循环中的S),这样声明就不会离使用太远。
当声明的右侧使类型变得明显时,在声明局部变量时使用var。
例如:
Dictionary<string, string> map = new Dictionary<string, string>();应该是
var map = new Dictionary<string, string>();在声明循环变量时,还应该始终使用var。
foreach(var pair in values)像这样的台词:
propList.Add(new Property<string>(){ DefaultValue = @"C:\...\...", PropertyName = "log_path"});可以通过在多条线上扩展,它可以简化可读性,并且不再需要滚动。
结果:
propList.Add(new Property<string>()
{
DefaultValue = @"C:\...\...",
PropertyName = "log_path"
});区域在方法之外是有争议的,但是每当我看到方法中的某个区域时,几乎可以肯定地保证该区域的内容应该被重构到它自己的方法中。您在原始代码中遗漏了一些行,因此这将是留给您的判断调用。
至于你的投诉:
if((bool)Properties.PropertyList["log_enabled"].GetValue()) //log...GetValue()到底为什么会存在?
为什么不直接在界面中使用通用的GetActualValue()呢?
public interface IProperty
{
bool IsSet { get; set; }
string PropertyName { get; set; }
T GetValue<T>();
}然后调用GetValue<bool>()并让它返回一个布尔值,不需要装箱或取消装箱。
如果是错误的类型,则抛出异常,或者使用空值进行排序。
https://codereview.stackexchange.com/questions/71312
复制相似问题