序列化Hashtable

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()方法。所以就用它来偷梁换柱一下了。


Item是自定义的一个类。没什么具体的意义。


Item是自定义的一个类。没什么具体的意义。

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

         }

 

         ICollection 成员#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

 

         IEnumerable 成员#region IEnumerable 成员

 

         public IEnumerator GetEnumerator() {

              return list.GetEnumerator();

         }

 

         #endregion

}

这样偷一下,上面的这个MyCollection类就是可以被序列化的了,然后把SortedList其他属性包一下,就基本可以当成一个SortedList使用了,说它是Hashtable也差不多吧――外表基本看不出来。

不过局限性还是有喽。它的Add方法的参数,与Item属性的类型必须是强类型的,不能用Objcet。用Object类型,临时文件是可以生成,serialize = new XmlSerializer(typeof(Myclass)); 这一句是可以通过没异常了。但真正序列化的时候,除非是一些基本的数据类型,否则它不知道如何去把那个类型写成相应的String,写XML文件就出错了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,能否告诉我您遇到的具体报错信息是什么呢?在不知道具体报错信息的情况下,我可以给您提供一些常见的问题和解决方法。 1. Hashtable 中的值类型不支持序列化 如果 Hashtable 中的值类型是自定义类型,而且没有实现序列化接口,那么在序列化时会报错。解决方法是实现序列化接口,比如在自定义类型中添加以下代码: ```csharp [Serializable] public class CustomType : ISerializable { // 类的其他代码 public void GetObjectData(SerializationInfo info, StreamingContext context) { // 实现序列化接口 } } ``` 2. 不能序列化 Hashtable .NET 框架中的 Hashtable 类是不支持序列化的,因为它没有标记为可序列化的。如果您尝试对 Hashtable 进行序列化,将会抛出 SerializationException 异常。解决方法是将 Hashtable 转换为支持序列化的类型,比如 Dictionary。 ```csharp Hashtable hashtable = new Hashtable(); // 在 hashtable 中添加一些键值对 Dictionary<string, object> dictionary = new Dictionary<string, object>(); foreach (DictionaryEntry entry in hashtable) { dictionary.Add((string)entry.Key, entry.Value); } BinaryFormatter formatter = new BinaryFormatter(); using (Stream stream = new FileStream("hashtable.bin", FileMode.Create, FileAccess.Write, FileShare.None)) { formatter.Serialize(stream, dictionary); } ``` 3. 序列化时文件被占用 如果在序列化时文件被占用,将会抛出 IOException 异常。解决方法是在打开文件时指定 FileShare.None,这样可以确保其他进程不能访问文件。 ```csharp using (Stream stream = new FileStream("hashtable.bin", FileMode.Create, FileAccess.Write, FileShare.None)) { formatter.Serialize(stream, hashtable); } ``` 希望以上方法能够帮助您解决问题。如果还有其他问题,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值