SharpDevelop 属性结构分析

属性结构位于Core/Property,先看属性系统的工作方式,如图:


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。
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;

看到这里,发现defaultvalue在这里不起任何作用,因为FromXmlElement()方法只是创建了一个以element为基础的新的DefaultProperties对象。所以可以简写为
            XmlNode node = ((XmlElement)obj).FirstChild;
            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;
            }
        }


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);
                }
            }
        }

SetValueFromXmlElement()方法,需要参考data\options\SharpDevelopProperties.xml文件,以理解一个新的属性对象是如何构造出来的。

4.ToXmlElement():与FromXmlElement()功能正好相反,不多说了。


posted @ 2007-07-25 08:28  包建强  Views(1121)  Comments(2Edit  收藏  举报