我不知道我怎样才能使一个通用的设置类,希望你能帮助我。
首先,我想一个设置文件的解决方案。 为此,我创建了一个单身是这样的:
public sealed class Settings
{
private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();
public void Load(string fileName)
{
throw new NotImplementedException();
}
public void Save(string fileName)
{
throw new NotImplementedException();
}
public void Update()
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the propery.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
public string GetPropery(string propertyName)
{
return m_lProperties[propertyName].ToString() ?? String.Empty;
}
/// <summary>
/// Gets the propery.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns></returns>
public string GetPropery(string propertyName, string defaultValue)
{
if (m_lProperties.ContainsKey(propertyName))
{
return m_lProperties[propertyName].ToString();
}
else
{
SetProperty(propertyName, defaultValue);
return defaultValue;
}
}
/// <summary>
/// Sets the property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="value">The value.</param>
public void SetProperty(string propertyName, string value)
{
if (m_lProperties.ContainsKey(propertyName))
m_lProperties[propertyName] = value;
else
m_lProperties.Add(propertyName, value);
}
}
但我认为,更好的办法是,属性中的类,我可以通过反射得到的属性。
- 你能帮助我实现这样的事情?
- 是否有可能给性能属性,如“加密=真”? - 请告诉我保存/在XML文件中加载设置的最佳方法是什么?
更新
下面是一个例子,如何使用环境下的实际:
class Test()
{
private string applicationPath;
private string configurationPath;
private string configurationFile;
public Test()
{
applicationPath = Settings.Instance.GetPropery("ApplicationPath", AppDomain.CurrentDomain.BaseDirectory);
configurationPath = Settings.Instance.GetPropery("ConfigurationPath", "configurations");
configurationFile = Settings.Instance.GetPropery("ConfigurationFile", "application.xml");
// ... Load file with all settings from all classes
}
这这里是从我自己的代码,而一个相关位。
public class MyObject
{
public string StringProperty {get; set;}
public int IntProperty {get; set;}
public object this[string PropertyName]
{
get
{
return GetType().GetProperty(PropertyName).GetGetMethod().Invoke(this, null);
}
set
{
GetType().GetProperty(PropertyName).GetSetMethod().Invoke(this, new object[] {value});
}
}
}
它所允许的话,是这样的:
MyObject X = new MyObject();
//Set
X["StringProperty"] = "The Answer Is: ";
X["IntProperty"] = 42;
//Get - Please note that object is the return type, so casting is required
int thingy1 = Convert.ToInt32(X["IntProperty"]);
string thingy2 = X["StringProperty"].ToString();
更新:更多的解释其工作原理是反射性的访问属性 ,属性是从该领域的不同,他们使用getter和setter方法,而不是被直接声明和访问。 如果空检查从的getProperty回报,而不是简单地假设它的工作原理,你可以使用相同的方法来获得字段,或者也得到场。 此外,作为另一种意见指出,这将如果你调用它是不存在的属性,因为它缺乏任何形式的错误捕获打破。 我发现在最简单的可能形式,而不是它最强大的表单的代码。
至于财产属性....这需要索引要与使用它的类里面创建(或父类,我有我的BaseObject
),所以在内部就可以实现给定的属性的属性,然后应用开关或防止当它们被访问的属性的检查。 也许让所有的属性,你实现一些其他的自定义类Object Value; Bool Encrypted;
Object Value; Bool Encrypted;
然后从那里需要进行这项工作,它真的只是取决于你想多么花哨得到你想要多少代码编写。
我不reccommend的地方也可能没有它使用反射,因为它很慢。
我没有思考和加密原型例如:
public sealed class Settings
{
private static readonly HashSet<string> _propertiesForEncrypt = new HashSet<string>(new string[] { "StringProperty", "Password" });
private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();
public void Load(string fileName)
{
// TODO: When you deserialize property which contains into "_propertiesForEncrypt" than Decrypt this property.
throw new NotImplementedException();
}
public void Save(string fileName)
{
// TODO: When you serialize property which contains into "_propertiesForEncrypt" than Encrypt this property.
throw new NotImplementedException();
}
public void Update()
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the propery.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <returns></returns>
public object GetPropery(string propertyName)
{
if (m_lProperties.ContainsKey(propertyName))
return m_lProperties[propertyName];
return null;
}
/// <summary>
/// Gets the propery.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns></returns>
public object GetPropery(string propertyName, object defaultValue)
{
if (m_lProperties.ContainsKey(propertyName))
{
return m_lProperties[propertyName].ToString();
}
else
{
SetProperty(propertyName, defaultValue);
return defaultValue;
}
}
/// <summary>
/// Sets the property.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="value">The value.</param>
public void SetProperty(string propertyName, object value)
{
if (m_lProperties.ContainsKey(propertyName))
m_lProperties[propertyName] = value;
else
m_lProperties.Add(propertyName, value);
}
// Sample of string property
public string StringProperty
{
get
{
return GetPropery("StringProperty") as string;
}
set
{
SetProperty("StringProperty", value);
}
}
// Sample of int property
public int IntProperty
{
get
{
object intValue = GetPropery("IntProperty");
if (intValue == null)
return 0; // Default value for this property.
return (int)intValue;
}
set
{
SetProperty("IntProperty", value);
}
}
}
使用动态类是这样的: https://gist.github.com/3914644 yourObject.stringProperty或yourObject.intProperty:所以你可以为访问您的属性
其中一个最大的问题是,有没有干净的方式来反序列化对象为对象。 如果你不提前知道什么时间该对象的类型必须是,它非常努力地工作着。 因此,我们有一个替代的解决方案,存储类型的信息。
鉴于其没有上市,我会提供什么样的,我认为一个示例XML,以及使用它的方法和访问属性本身的方法。 您正在使用get和set属性的功能是为是功能性的,并要求没有变化。
在单独的类,你需要确保在类引用相关属性设置类在自己的get / set方法
public int? MyClassProperty
{
get
{
return (int?)Settings.Instance.GetProperty("MyClassProperty");
}
set
{
Settings.Instance.SetProperty("MyClassProperty", value);
}
}
在您加载和保存功能,你将要使用序列化,具体而言, XmlSerializer
。 要做到这一点,你需要适当声明你的设置列表。 为此,我将实际使用自定义类。
更新,以便正确装载
public class AppSetting
{
[XmlAttribute("Name")]
public string Name { get; set; }
[XmlAttribute("pType")]
public string pType{ get; set; }
[XmlIgnore()]
public object Value{ get; set; }
[XmlText()]
public string AttributeValue
{
get { return Value.ToString(); }
set {
//this is where you have to have a MESSY type switch
switch(pType)
{ case "System.String": Value = value; break;
//not showing the whole thing, you get the idea
}
}
}
然后,而不仅仅是一本字典,你会是这样的:
public sealed class Settings
{
private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings());
private Dictionary<string, object> m_lProperties = new Dictionary<string, object>();
private List<AppSetting> mySettings = new List<AppSetting>();
您的负载功能将是一个简单的反序列化
public void Load(string fileName)
{//Note: the assumption is that the app settings XML will be defined BEFORE this is called, and be under the same name every time.
XmlSerializer ser = new XmlSerializer(typeof(List<AppSetting>));
FileStream fs = File.Open(fileName);
StreamReader sr = new StreamReader(fs);
mySettings = (List<AppSetting>)ser.DeSerialize(sr);
sr.Close();
fs.Close();
//skipping the foreach loop that will add all the properties to the dictionary
}
保存功能将基本上需要扭转它。
public void Save(string fileName)
{
//skipping the foreach loop that re-builds the List from the Dictionary
//Note: make sure when each AppSetting is created, you also set the pType field...use Value.GetType().ToString()
XmlSerializer ser = new XmlSerializer(typeof(List<AppSetting>));
FileStream fs = File.Open(fileName, FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
//get rid of those pesky default namespaces
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
ser.Serialize(sw, mySettings, ns);
sw.Flush();
sw.Close();
fs.Close();
mySettings = null;//no need to keep it around
}
和XML将类似于这样的事情:
更新
<ArrayOfAppSetting>
<AppSetting Name="ApplicationPath" pType="System.String">C:\Users\ME\Documents\Visual Studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1\bin\Debug\</AppSetting>
<AppSetting Name="ConfigurationPath" pType="System.String">configurations</AppSetting>
<AppSetting Name="ConfigurationFile" pType="System.String">application.xml</AppSetting>
<AppSetting Name="prop" pType="System.Int32">1</AppSetting>
</ArrayOfAppSetting>
我发现使用中间这个例子中List<>
因为事实证明,你不能使用任何与XmlSerializer的实现IDictionary中。 这将无法完成初始化,这是行不通的。
您可以沿着字典创建和维护该列表,也可以更换名单的字典...请确保您有检查,以验证“名称”是唯一的,或者你可以简单地忽略列表中除了保存期间加载操作(这是我写的怎么这个例子)
更新这真的只能用原始类型效果很好 (INT,双,字符串,等等),而是因为你直接存储类型,你可以使用任何你想要的自定义类型,因为你知道它是什么,用它做,你只需要处理它的AttributeValue的设置方法
另一个更新:如果您只存储而不是所有类型的对象的字符串,...这很可笑的简单。 摆脱了XmlIgnore value
和pType
,然后自动实现AttributeValue
。 热潮,完成。 这会限制你的字符串和其他原语虽然,确保了get / set在适当投他们的其他类值...但它是一个更简单,更容易实现。
文章来源: Best way to implement generic setting class - Get/Set Properties reflected?