xml序列化集合

 
Xml序列化是将对象中的字段和值序列化为xml流,保存为Xml文件的格式。反序列化是将类从Xml流中读出。
主要用到的类为:XmlSerializer,它的主要方法有Serialize和Deserialize,用来序列化和反序列化Xml。 XmlSerializer构造函数中的参数Type type,用来表示要进行序列化的类的类型,可以通过typeof(类名)来获取。Serialize有两个参数Stream stream和Object o,分别表示序列化的流和要序列化的对象。Deserialize有一个参数Stream stream表示要反序列化的流。
可以用属性来控制Xml的序列化,XmlAttribute属性表示对象成员序列化为Xml属性,
XmlElement 属性表示要将成员序列化为Xml元素,XmlArray属性应用于数组成员,数组的成员将成为Xml数组的成员。XmlRoot属性表示要序列化为Xml 的根元素。在这些属性中都可以进一步制定元素的名称,是否为空等。XmlRoot属性中还可以制定命名空间。
            [XmlArray(ElementName = "Items")]
            [XmlElement(IsNullable = false)]
            [XmlRoot(ElementName="PurchaseOrder",Namespace = “http://www.w3.org”)]
            [XmlAttribute]
XML序列化这个东西挺搞人的,当你的Class里有Hashtable这样的东西的时候,在序列化的时候,在
XmlSerializer serialize = new XmlSerializer(typeof(myClass));
这一句上会出来一个“反射类型时出错”的错误。其实就是那个Hashtable在搞鬼,直接把上面一句换成
XmlSerializer serialize = new XmlSerializer(typeof(Hashtable));
罪魁祸首就出来了。这次是:“不支持类型 System.Collections.Hashtable,因为它实现 IDictionary”。原来XML序列化时对集合类还有一些比较特殊的要求。
  
那先来看一个可以正常序列化的集合类――Arraylist:
serialize = new XmlSerializer(typeof(ArrayList));
在序列化过程中临时生成的文件中可以发现如下的语句:
                    WriteStartElement(@"ArrayOfAnyType", @"");
                   for (int ia = 0; ia < a.Count; ia++ ) {
                        Write1_Object(@"anyType", @"", ((System.Object)a[ia]), true, false);
                    }
WriteEndElement();
对于集合类,在XML序列化过程中都是要如上所述来写XML的,显然的,对于实现了IDictionary接口的集合来讲,上面那个for循环是走不通的。因为对于IDictionary来讲Item属性(也就是C#里的[]这个东西,也叫索引器,名字反正有点乱啦)是这样定义的:
[C#]
object this[
   object key
] {get; set;} object this[
   object key
] {get; set;}
 
上面是从结果上看,猜想最终序列化的时候,集合类是要以上面那样的循环方式进行序列化的,而实现了IDictionary接口的类对于那样的方式是不灵的,所以在生成临时文件的时候就不让它生成了,反正生成的DLL也是无法运行的,直接一个异常出来了。
 
其实在SDK上可以查到,关于XML序列化有这么一段:
XmlSerializer 可以以不同方式处理实现 IEnumerable ICollection 的类(条件是这些类满足某些要求)。实现 IEnumerable 的类必须实现带单个参数的公共 Add 方法。Add 方法的参数必须与从 GetEnumerator 方法返回的 IEnumerator.Current 属性所返回的类型一致(多态)。除实现 IEnumerable 外还实现 ICollection 的类(如 CollectionBase )必须有一个取整数的公共 Item 索引属性(在 C# 中为索引器),并且它必须有一个整数类型的公共 Count 属性。传递给 Add 方法的参数必须与从 Item 属性返回的类型相同或与该类型的某个基的类型相同。对于实现 ICollection 的类,要序列化的值将从索引 Item 属性检索,而不是通过调用 GetEnumerator 来检索。另外请注意,除返回另一个集合类(实现 ICollection 的集合类)的公共字段之外,将不序列化公共字段和属性。
无法满足上述条件的都会抛出相应的异常,而实现了IDictionary接口的类显然是无法满足的,.net在实现的时候,一开始就先判断是不是实现了IDictionary接口,发现实现了这个接口的直接就出来了,下面什么Add方法、Item属性呀都不管了。
还有一点,就是
l        类(Class这一级)――包括集合类与非集合,
l        非集合类 需要序列化的属性里的访问方法(不用序列化的属性例外),
l        在集合类里,上面提到过的Add方法,Item属性、Count属性、Current属性的访问方法等,
如果有过SecurityAttribute声明的也是无法序列化的。不过现在写代码那个SecurityAttribute用得是甚少――这个方面的东西除了照例子依样画葫芦过一下在实践中根本是没有涉足。
 
要序列化Hashtable其实就只是少一个整数类型的Item属性而已,在这上面是没有什么办法了。想到SortedList这个东西很多方面跟Hashtable差不多,不过它还能依序取得集合中的元素,只是用的不是整数类型的Item属性,而是用GetByIndex()方法。所以就用它来偷梁换柱一下了。
//    [EnvironmentPermission(SecurityAction.Assert)]

     
public  class  MyCollection : ICollection  {

         
private SortedList list = new SortedList();

         
public MyCollection () {

 

         }


         

//       [EnvironmentPermission(SecurityAction.Assert)]

         
public void Add(Item item) {

              list.Add(item.ID,item);

         }


 

         
public Item this[int index] {

              
get {return (Item)list.GetByIndex(index);}

         }


 

         
#region ICollection 成员

 

         
public bool IsSynchronized {

              
get {

                   
return false;

              }


         }


 

         
public int Count {

              
get {

                   
return list.Count;

              }


         }


 

     [EnvironmentPermission(SecurityAction.Assert)]

         
public void CopyTo(Array array, int index) {

              list.CopyTo(array,index);

         }


 

         
public object SyncRoot {

              
get {

                   
return this;

              }


         }


 

         
#endregion


 

         
#region IEnumerable 成员

 

         
public IEnumerator GetEnumerator() {

              
return list.GetEnumerator();

         }


 

         
#endregion


}



Item是自定义的一个类。没什么具体的意义。
 
这样偷一下,上面的这个MyCollection类就是可以被序列化的了,然后把SortedList其他属性包一下,就基本可以当成一个SortedList使用了,说它是Hashtable也差不多吧――外表基本看不出来。
不过局限性还是有喽。它的Add方法的参数,与Item属性的类型必须是强类型的,不能用Objcet。用Object类型,临时文件是可以生成, serialize = new XmlSerializer(typeof(Myclass)); 这一句是可以通过没异常了。但真正序列化的时候,除非是一些基本的数据类型,否则它不知道如何去把那个类型写成相应的String,写XML文件就出错了。
附加一些冗于的资料:
  1     /// 
  2    /// 序列化类。
  3    /// 

  4      public   class  Serializer
  5      {
  6        //防止被实例化。
  7        private Serializer()
  8        {
  9
 10        }

 11        /// 
 12        /// 静态构造函数仅在设置CanBinarySerialize值中使用一次。
 13        /// 

 14        static Serializer()
 15        {
 16            SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.SerializationFormatter);
 17            try
 18            {
 19                sp.Demand();
 20                CanBinarySerialize = true;
 21            }

 22            catch (SecurityException)
 23            {
 24                CanBinarySerialize = false;
 25            }

 26        }

 27        /// 
 28        /// 获取二进制序列化是否被使用。
 29        /// 

 30        public static readonly bool CanBinarySerialize;
 31        /// 
 32        /// 将对象转化成二进制的数组。
 33        /// 

 34        /// 用于转化的对象。
 35        /// 返回转化后的数组,如果CanBinarySerialize为false则返回null。

 36        public static byte[] ConvertToBytes(object objectToConvert)
 37        {
 38            byte[] byteArray = null;
 39
 40            if (CanBinarySerialize)
 41            {
 42                BinaryFormatter binaryFormatter = new BinaryFormatter();
 43                using (MemoryStream ms = new MemoryStream())
 44                {
 45
 46                    binaryFormatter.Serialize(ms, objectToConvert);
 47                    //设置是内存存储位置为0。
 48                    ms.Position = 0;
 49                    //读取数组。
 50                    byteArray = new Byte[ms.Length];
 51                    ms.Read(byteArray, 0, byteArray.Length);
 52                    ms.Close();
 53                }

 54            }

 55            return byteArray;
 56        }

 57        /// 
 58        /// 将对象以二进制形式存储到硬盘中。
 59        /// 

 60        /// 用于保存的对象。
 61        /// 文件路径。
 62        /// 如果存储成功则返回true,否则返回false。

 63        public static bool SaveAsBinary(object objectToSave, string path)
 64        {
 65            if (objectToSave != null && CanBinarySerialize)
 66            {
 67                byte[] ba = ConvertToBytes(objectToSave);
 68                if (ba != null)
 69                {
 70                    using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
 71                    {
 72                        using (BinaryWriter bw = new BinaryWriter(fs))
 73                        {
 74                            bw.Write(ba);
 75                            return true;
 76                        }

 77                    }

 78                }

 79            }

 80            return false;
 81        }

 82        /// 
 83        ///将对象转化为XML格式文件,该对象必须用[Serialize]标记,否则将抛出错误。
 84        /// 

 85        /// 用于序列化的标记。
 86        /// 返回XML文本,如果对象为空则返回null。

 87        public static string ConvertToString(object objectToConvert)
 88        {
 89            string xml = null;
 90
 91            if (objectToConvert != null)
 92            {
 93                //获取当前序列化对象。
 94                Type t = objectToConvert.GetType();
 95
 96                XmlSerializer ser = new XmlSerializer(t);
 97                //将序列化的结果保存到XML中。
 98                using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
 99                {
100                    ser.Serialize(writer, objectToConvert);
101                    xml = writer.ToString();
102                    writer.Close();
103                }

104            }

105
106            return xml;
107        }

108        /// 
109        /// 将对象序列化后以XML格式存储于文件中。
110        /// 

111        /// 用于序列化的对象。
112        /// 用于存储的文件路径。

113        public static void SaveAsXML(object objectToConvert, string path)
114        {
115            if (objectToConvert != null)
116            {
117                Type t = objectToConvert.GetType();
118
119                XmlSerializer ser = new XmlSerializer(t);
120
121                using (StreamWriter writer = new StreamWriter(path))
122                {
123                    ser.Serialize(writer, objectToConvert);
124                    writer.Close();
125                }

126            }

127
128        }

129        /// 
130        /// 将一个二进制的数组转化为对象,必须通过类型转化自己想得到的相应对象。如果数组为空则返回空。
131        /// 

132        /// 用于转化的二进制数组。
133        /// 返回转化后的对象实例,如果数组为空,则返回空对象。

134        public static object ConvertToObject(byte[] byteArray)
135        {
136            object convertedObject = null;
137            if (CanBinarySerialize && byteArray != null && byteArray.Length > 0)
138            {
139                BinaryFormatter binaryFormatter = new BinaryFormatter();
140                using (MemoryStream ms = new MemoryStream())
141                {
142                    ms.Write(byteArray, 0, byteArray.Length);
143
144                    ms.Position = 0;
145
146                    if (byteArray.Length > 4)
147                        convertedObject = binaryFormatter.Deserialize(ms);
148
149                    ms.Close();
150                }

151            }

152            return convertedObject;
153        }

154        /// 
155        /// 将文件的数据转化为对象。
156        /// 

157        /// 文件路径。
158        /// 希望得到的对象。
159        /// 返回反序列化的对象。

160        public static object ConvertFileToObject(string path, Type objectType)
161        {
162            object convertedObject = null;
163
164            if (path != null && path.Length > 0)
165            {
166                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
167                {
168                    XmlSerializer ser = new XmlSerializer(objectType);
169                    convertedObject = ser.Deserialize(fs);
170                    fs.Close();
171                }

172            }

173            return convertedObject;
174        }

175        /// 
176        /// 将XML格式的字符串反序列化为实例对象。 
177        /// 

178        /// Xml格式字符串。
179        /// 反序列化后所期望的对象。
180        /// 反序列化后所期望的对象,如果字符串为空,则返回空对象。

181        public static object ConvertToObject(string xml, Type objectType)
182        {
183            object convertedObject = null;
184
185            if (!WebHelper.IsNullOrEmpty(xml))
186            {
187                using (StringReader reader = new StringReader(xml))
188                {
189                    XmlSerializer ser = new XmlSerializer(objectType);
190                    convertedObject = ser.Deserialize(reader);
191                    reader.Close();
192                }

193            }

194            return convertedObject;
195        }

196        /// 
197        /// 将XML节点反序列化为实例对象。 
198        /// 

199        /// 用于反序列化的XML节点。
200        /// 反序列化后所期望的对象。
201        /// 反序列化后所期望的对象,如果字符串为空,则返回空对象。

202        public static object ConvertToObject(XmlNode node, Type objectType)
203        {
204            object convertedObject = null;
205
206            if (node != null)
207            {
208                using (StringReader reader = new StringReader(node.OuterXml))
209                {
210
211                    XmlSerializer ser = new XmlSerializer(objectType);
212
213                    convertedObject = ser.Deserialize(reader);
214
215                    reader.Close();
216                }

217            }

218            return convertedObject;
219        }

220        /// 
221        /// 加载一个二进制文件并将其转化为实例对象。
222        /// 

223        /// 文件路径。
224        /// 返回转化后的实例对象。

225        public static object LoadBinaryFile(string path)
226        {
227            if (!File.Exists(path))
228                return null;
229
230            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
231            {
232                BinaryReader br = new BinaryReader(fs);
233                byte[] ba = new byte[fs.Length];
234                br.Read(ba, 0, (int)fs.Length);
235                return ConvertToObject(ba);
236            }

237        }

238        /// 
239        /// 将字符串序列化类型,第一个为键,第二位与其相对应的值。
240        /// 

241        /// NameValueCollection中的keys键。
242        /// NameValueCollection中的keys键对应的value。
243        /// 基于key-value格式的NameValeCollection集合对象。
244        /// 
245        /// string keys = "key1:S:0:3:key2:S:3:2:";
246        /// string values = "12345";
247        /// 则这个所得的NameValueCollection结果中包含两个键(key1和key2),他们所对应的值分别为(123和45)。
248        /// 其中:"key1:S:0:3"的key1表示键,S表示字符类型,0表示values起始的位置,3表示values结束的位置。
249        /// 

250        public static NameValueCollection ConvertToNameValueCollection(string keys, string values)
251        {
252            NameValueCollection nvc = new NameValueCollection();
253
254            if (keys != null && values != null && keys.Length > 0 && values.Length > 0)
255            {
256                char[] splitter = new char[1':' };
257                string[] keyNames = keys.Split(splitter);
258
259                for (int i = 0; i < (keyNames.Length / 4); i++)
260                {
261                    int start = int.Parse(keyNames[(i * 4+ 2], CultureInfo.InvariantCulture);
262                    int len = int.Parse(keyNames[(i * 4+ 3], CultureInfo.InvariantCulture);
263                    string key = keyNames[i * 4];
264
265                    //Future version will support more complex types    
266                    if (((keyNames[(i * 4+ 1== "S"&& (start >= 0)) && (len > 0&& (values.Length >= (start + len)))
267                    {
268                        nvc[key] = values.Substring(start, len);
269                    }

270                }

271            }

272
273            return nvc;
274        }

275        /// 
276        ///  基于NameValueCollection对象序列化成keys和values的字符串。
277        /// 

278        /// 用于序列化的NameValueCollection对象。
279        /// ref格式的参数keys将转化为NameValueCollection中的key。
280        /// ref格式的参数values将转化为NameValueCollection中的value。

281        public static void ConvertFromNameValueCollection(NameValueCollection nvc, ref string keys, ref string values)
282        {
283            if (nvc == null || nvc.Count == 0)
284                return;
285
286            StringBuilder sbKey = new StringBuilder();
287            StringBuilder sbValue = new StringBuilder();
288
289            int index = 0;
290            foreach (string key in nvc.AllKeys)
291            {
292                if (key.IndexOf(':'!= -1)
293                    throw new ArgumentException("ExtendedAttributes Key can not contain the character /":/"");
294
295                string v = nvc[key];
296                if (!WebHelper.IsNullOrEmpty(v))
297                {
298                    sbKey.AppendFormat("{0}:S:{1}:{2}:", key, index, v.Length);
299                    sbValue.Append(v);
300                    index += v.Length;
301                }

302            }

303            keys = sbKey.ToString();
304            values = sbValue.ToString();
305        }

306    }
 
  在SiteSettings.cs中可以发现有些属性加有[XmlIgnore]标记,这是在序列化和反序列化时对该属性都不起作用,如SettingsID等在数据库中都已经存在字段名。从代码中我们可以看到,将一个NameValueCollection集合序列化和反序列化,其实键和值对存储在一个结构中,这个结构就是:
 1      public   struct  SerializerData
 2      {
 3        /// 
 4        /// 序列化NameValueCollection集合时用于保存Keys的字符串。
 5        /// 

 6        public string Keys;
 7        /// 
 8        ///  序列化NameValueCollection集合时用于保存Values的字符串。
 9        /// 

10        public string Values;
11    }

你可能感兴趣的:(Asp.net)