1. 程式人生 > >不支援型別 Quartz.JobDataMap,因為它實現 IDictionary。

不支援型別 Quartz.JobDataMap,因為它實現 IDictionary。

     在嘗試 把Quartz定時器功能做成 WebService的過程中。因為想在客戶端傳遞兩個引數:一個是cron格式的時間,另一個是相應時間的類job類(特定時間觸發的特定工作類)。設計web服務的過程中出現了

    當你的類中有hashitable等東西的時候,序列化的時候就會出現“反射型別時出錯”提示。其實就是哈市table搞的鬼。例如

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

         }

         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

}

Item是自定義的一個類。沒什麼具體的意義。

這樣偷一下,上面的這個MyCollection類就是可以被序列化的了,然後把SortedList其他屬性包一下,就基本可以當成一個SortedList使用了,說它是Hashtable也差不多吧――外表基本看不出來。

不過侷限性還是有嘍。它的Add方法的引數,與Item屬性的型別必須是強型別的,不能用Objcet。用Object型別,臨時檔案是可以生成,serialize = new XmlSerializer(typeof(Myclass)); 這一句是可以通過沒異常了。但真正序列化的時候,除非是一些基本的資料型別,否則它不知道如何去把那個型別寫成相應的String,寫Xml檔案就出錯了。

同樣的道理,我的這個錯誤也是因為Quartz.JobDataMap 不能被序列化。如何解決研究中》》》