IXmlCovartable接口提供了对象与XML节点互相转换的方法,可以认为是序列化的另一种实现方式。据作者说,这两个方法的实现要比序列化速度快很多。
IProperties是主接口,应用程序其他部分都通过调用该接口进行工作。它提供了对属性的读写操作,以及一个自身对象的复制方法。
DefaultProperties是IProperties接口的默认实现方式,其中的几个实现方法确实有点意思。
这个类其实是个注册工厂,所有属性按需创建,都存在properties这个hashtable中。
1.先说
1.先说GetProperty(),这个方法有若干重载,见下:
1 public object GetProperty(string key, object defaultvalue)
2 {
3 if (!properties.ContainsKey(key)) {
4 if (defaultvalue != null) {
5 properties[key] = defaultvalue;
6 }
7 return defaultvalue;
8 }
9
10 object obj = properties[key];
11
12 if (defaultvalue is IXmlConvertable && obj is XmlElement) {
13 obj = properties[key] = ((IXmlConvertable)defaultvalue).FromXmlElement((XmlElement)((XmlElement)obj).FirstChild);
14 }
15 return obj;
16 }
2-8行是在hashtable中找不到key的处理办法:即新建key并设为defaultvalue,同时返回defaultvalue。2 {
3 if (!properties.ContainsKey(key)) {
4 if (defaultvalue != null) {
5 properties[key] = defaultvalue;
6 }
7 return defaultvalue;
8 }
9
10 object obj = properties[key];
11
12 if (defaultvalue is IXmlConvertable && obj is XmlElement) {
13 obj = properties[key] = ((IXmlConvertable)defaultvalue).FromXmlElement((XmlElement)((XmlElement)obj).FirstChild);
14 }
15 return obj;
16 }
10-15行,如果hashtable中有这个key,那么取出来赋值给obj。如果defaultvalue派生自IXmlCovertable接口同时obj又是XmlElement——13行就难看懂了,真奇怪为什么牛人都喜欢写这么长的语句。把它拆开就是:
XmlNode node = ((XmlElement)obj).FirstChild;
XmlElement element = (XmlElement)node; //key值应该对应obj的第一个字节点
IXmlConvertable ixc = (IXmlConvertable)defaultvalue; //将DefaultValue拆箱为IXmlConvertable
object temp = ixc.FromXmlElement(element);
obj = properties[key] = temp;
XmlElement element = (XmlElement)node; //key值应该对应obj的第一个字节点
IXmlConvertable ixc = (IXmlConvertable)defaultvalue; //将DefaultValue拆箱为IXmlConvertable
object temp = ixc.FromXmlElement(element);
obj = properties[key] = temp;
看到这里,发现defaultvalue在这里不起任何作用,因为FromXmlElement()方法只是创建了一个以element为基础的新的DefaultProperties对象。所以可以简写为
XmlNode node = ((XmlElement)obj).FirstChild;
XmlElement element = (XmlElement)node; //这里element就是obj对象的一个clone
object temp = FromXmlElement(element);
obj = properties[key] = temp;
XmlElement element = (XmlElement)node; //这里element就是obj对象的一个clone
object temp = FromXmlElement(element);
obj = properties[key] = temp;
这也就是第13行的意思,既然hashtable中有这个key值,就把它取出来,得到它的第一个子节点,以此为基础重新构造出一个新对象,赋予obj并返回。——这里我不太明白,需要debug到Runtime才会领悟。
补注:GetProperty有一个Enum版的重载,对我们写程序很有参考价值:
public System.Enum GetProperty(string key, System.Enum defaultvalue)
{
try {
return (System.Enum)Enum.Parse(defaultvalue.GetType(), GetProperty(key, (object)defaultvalue).ToString());
} catch (Exception) {
return defaultvalue;
}
}
{
try {
return (System.Enum)Enum.Parse(defaultvalue.GetType(), GetProperty(key, (object)defaultvalue).ToString());
} catch (Exception) {
return defaultvalue;
}
}
2.SetProperty(string key, object val)
如果新旧属性值不同,就为该key设置新的属性,并激发事件OnPropertyChanged,这是一个virtual可覆写的事件,不同的场景对该事件有不同的实现,这个事件的自定义参数PropertyEventArgs继承了EventArgs,并随身携带着key/oldValue/newValue。
3.FromXmlElement():根据XmlElement参数构造出一个新的DefaultProperty对象来,需要辅助函数SetValueFromXmlElement()的配合:
public virtual object FromXmlElement(XmlElement element)
{
DefaultProperties defaultProperties = new DefaultProperties();
defaultProperties.SetValueFromXmlElement(element);
return defaultProperties;
}
protected void SetValueFromXmlElement(XmlElement element)
{
XmlNodeList nodes = element.ChildNodes;
foreach (XmlElement el in nodes)
{
if (el.Name == "Property")
{
properties[el.Attributes["key"].InnerText] = el.Attributes["value"].InnerText;
}
else if (el.Name == "XmlConvertableProperty")
{
properties[el.Attributes["key"].InnerText] = el;
}
else
{
throw new UnknownPropertyNodeException(el.Name);
}
}
}
{
DefaultProperties defaultProperties = new DefaultProperties();
defaultProperties.SetValueFromXmlElement(element);
return defaultProperties;
}
protected void SetValueFromXmlElement(XmlElement element)
{
XmlNodeList nodes = element.ChildNodes;
foreach (XmlElement el in nodes)
{
if (el.Name == "Property")
{
properties[el.Attributes["key"].InnerText] = el.Attributes["value"].InnerText;
}
else if (el.Name == "XmlConvertableProperty")
{
properties[el.Attributes["key"].InnerText] = el;
}
else
{
throw new UnknownPropertyNodeException(el.Name);
}
}
}
读SetValueFromXmlElement()方法,需要参考data\options\SharpDevelopProperties.xml文件,以理解一个新的属性对象是如何构造出来的。
4.ToXmlElement():与FromXmlElement()功能正好相反,不多说了。