C# 实现泛型设置类的最佳方法-获取/设置反映的属性?
我不知道如何创建一个通用设置类,希望您能帮助我。C# 实现泛型设置类的最佳方法-获取/设置反映的属性?,c#,xml,reflection,properties,settings,C#,Xml,Reflection,Properties,Settings,我不知道如何创建一个通用设置类,希望您能帮助我。 首先,我想要一个单一的设置文件解决方案。为此,我创建了这样一个单例: public sealed class Settings { private static readonly Lazy<Settings> _instance = new Lazy<Settings>(() => new Settings()); private Dictionary<string, object> m_lPro
首先,我想要一个单一的设置文件解决方案。为此,我创建了这样一个单例:
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);
}
}
这是我自己代码中的一个相当相关的部分
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的返回值为null,而不是简单地假设它可以工作。另外,正如在另一条评论中指出的那样,如果您使用不存在的属性按原样调用它,这将中断,因为它缺少任何形式的错误捕获。我以最简单的形式展示了代码,而不是最健壮的形式
就属性属性而言……该索引器需要在您想要使用它的类(或父类,我在我的
BaseObject
上有它)内部创建,因此您可以在内部对给定属性实现属性,然后在访问属性时对其应用开关或检查。可能会将所有属性设置为实现对象值的其他自定义类;布尔加密代码>然后根据需要对其进行处理,这实际上取决于您想要获得的效果和想要编写的代码量。使用这样的动态类:这样您就可以访问您的属性:yourObject.stringProperty或yourObject.intProperty我不建议在可能没有反射的地方使用反射,因为它非常慢
我的示例没有反射和加密原型:
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);
}
}
}
公共密封类设置
{
私有静态只读哈希集_propertiesForEncrypt=新哈希集(新字符串[]{“StringProperty”,“Password”});
private static readonly Lazy _instance=new Lazy(()=>new Settings());
私有字典m_lProperties=新字典();
公共无效加载(字符串文件名)
{
//TODO:反序列化包含到“\u Properties ForEnCrypt”中的属性时,请解密此属性。
抛出新的NotImplementedException();
}
公共作废保存(字符串文件名)
{
//TODO:将包含的属性序列化为“\u Properties ForEnCrypt”时,请加密此属性。
抛出新的NotImplementedException();
}
公共无效更新()
{
抛出新的NotImplementedException();
}
///
///获取属性。
///
///属性的名称。
///
公共对象GetProperty(字符串propertyName)
{
if(m_lproperty.ContainsKey(propertyName))
返回m_lproperty[propertyName];
返回null;
}
///
///获取属性。
///
///属性的名称。
///默认值。
///
公共对象GetProperty(字符串propertyName,对象defaultValue)
{
if(m_lproperty.ContainsKey(propertyName))
{
返回m_lproperty[propertyName].ToString();
}
其他的
{
SetProperty(propertyName,defaultValue);
返回默认值;
}
}
///
///设置属性。
///
///属性的名称。
///价值。
公共void SetProperty(字符串propertyName,对象值)
{
if(m_lproperty.ContainsKey(propertyName))
m_lproperty[propertyName]=值;
其他的
m_lproperty.Add(propertyName,value);
}
//字符串属性的示例
公共字符串字符串属性
{
得到
{
返回GetProperty(“StringProperty”)作为字符串;
}
设置
{
SetProperty(“StringProperty”,值);
}
}
//int属性的示例
公共int属性
{
得到
{
对象intValue=GetProperty(“IntProperty”);
if(intValue==null)
返回0;//此属性的默认值。
返回(int)int值;
}
设置
{
SetProperty(“IntProperty”,值);
}
}
}
最大的问题之一是没有清晰的方法将对象反序列化为对象。如果你事先不知道对象的类型,那么很难处理。所以我们有另一种解决方案,存储类型信息
因为它没有列出,我将提供我所考虑的示例XML,以及使用它的方法,以及访问属性本身的方法。用于获取和设置属性的函数按原样运行,不需要更改
在各个类中,您需要确保该类中的相关属性在其自己的get/set方法中引用Settings类
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>();
公共密封类设置
{
private static readonly Lazy _instance=new Lazy(()=>new Settings());
私有字典m_lProperties=新字典();
private List mySettings=new List();
加载函数将是一个简单的反序列化
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
}
公共无效加载(字符串文件名)
{//注意:假设应用程序设置XML将在调用之前定义,并且每次都使用相同的名称。
XmlSerializer ser=新的XmlSerializer(typeof(List));
FileStream fs=File.Open(文件名);
StreamReader sr=新的StreamReader(fs);
mySettings=(列表)ser。
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
}
<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>