共用方式為


資料合約中的集合型別

集合」(Collection) 是特定型別之項目的清單。在 .NET Framework 中,可以使用陣列或其他多種型別 (泛型清單、泛型 BindingList, StringCollectionArrayList) 來表示這類清單。例如,集合可能含有特定「客戶」的地址清單。不論實際型別為何,這些集合統稱為「清單集合」(List Collection)。

特殊形式的集合可以用來表示一個項目 (「索引鍵」) 與另一個項目 (「值」) 之間的關聯。在 .NET Framework 中,這些集合將表示成 Hashtable 及泛型字典等型別。例如,關聯集合可能會將城市 (「索引鍵」) 對應到其人口數目 (「值」)。不論實際型別為何,這些集合統稱為「字典集合」(Dictionary Collection)。

集合在資料合約模型中會受到特殊處理。

包括陣列與泛型集合等實作 IEnumerable 介面的型別,都會識別為集合。在這些型別中,實作 IDictionary 或泛型 IDictionary 介面的型別屬於字典集合,而其他所有型別則屬於清單集合。

關於集合型別的其他需求,例如包含稱為 Add 的方法和預設建構函式 (Constructor),都會在下列各節中詳細討論。這樣便可確保集合型別能夠序列化與還原序列化。這表示某些集合無法受到直接支援,例如,泛型 ReadOnlyCollection (因為它沒有預設的建構函式) 或 Stack (因為其新增項目的方法稱為 Push,而不是 Add)。不過,如需規避這些限制的詳細資訊,請參閱本主題稍後的「使用集合介面型別和唯讀集合」一節。

包含在集合中的型別必須是資料合約類型,否則必須是可序列化的型別。如需詳細資訊,請參閱 資料合約序列化程式支援的型別

如需 被視為有效集合的條件以及如何序列化集合的詳細資訊,請參閱本主題「進階集合規則」一節中有關序列化集合的資訊。

可互換的集合

相同型別的所有清單集合,都會被視為具有相同的資料合約 (除非有使用 CollectionDataContractAttribute 屬性來自訂這些集合,如本主題稍後所討論)。例如,下列資料合約是相等的。

這兩個資料合約都會產生與下列程式碼類似的 XML。

<PurchaseOrder>
    <customerName>…</customerName>
    <items>
        <Item>…</Item>
        <Item>…</Item>
        <Item>…</Item>
        …
    </items>
    <comments>
        <string>…</string>
        <string>…</string>
        <string>…</string>
        …
    </comments>
</PurchaseOrder>

集合可互換性讓您能夠使用像是已針對伺服器效能完成最佳化的集合型別,以及設計用來繫結至用戶端上之使用者介面元件的集合型別。

類似於清單集合,具有相同索引鍵和值型別的所有字典集合都會被視為具有相同的資料合約 (除非已由 CollectionDataContractAttribute 屬性自訂)。

就考慮集合的相等性而言,只有資料合約類型 (而非 .NET 型別) 會有影響。也就是說,如果 Type1 集合與 Type2 集合擁有相同的資料合約,Type1 與 Type2 就會被視為相等。

非泛型集合也會被視為與 Object 型別的泛型集合具有相同的資料合約 (例如,ArrayListObject 之泛型 List 的資料合約都是相等的)。

使用集合介面型別和唯讀集合

集合介面型別 (IEnumerableIDictionary、泛型 IDictionary,或是從這些介面衍生的介面) 也會被視為與實際集合型別具有相等的集合資料合約。這樣一來,便可將要序列化的型別宣告成集合介面型別,而其結果相同於假設是使用實際的集合型別的結果。例如,下列資料合約是相等的。

在進行序列化期間,當宣告的型別為介面時,使用的實際執行個體型別就可以是實作該介面的任何型別。先前所討論的限制 (包含預設建構函式和 Add 方法) 並不適用。例如,您可以將 Customer2 中的地址設定為地址之泛用 ReadOnlyCollection 的執行個體,即使無法直接宣告泛用 ReadOnlyCollection 型別的資料成員也是如此。

在進行還原序列化期間,如果宣告的型別為介面,序列化引擎便會選擇實作宣告之介面的型別,而且該型別會具現化。在此,已知的型別機制 (在資料合約已知型別中有所描述) 不會有任何效果;型別的選項已建置於 WCF。

自訂集合型別

您可以使用 CollectionDataContractAttribute 屬性來自訂集合型別,此屬性有數種用法。

請注意,自訂集合型別會影響集合的可互換性,所以我們一般會建議您盡可能避免套用這個屬性。如需 這個問題的詳細資訊,請參閱本主題稍後的「進階集合規則」一節。

集合資料合約命名

資料合約名稱中所述,命名集合型別的規則與命名一般資料合約類型的規則相似,不過其中仍有某些重要差異:

  • 使用 CollectionDataContractAttribute 屬性來自訂名稱,而不是使用 DataContractAttribute 屬性。CollectionDataContractAttribute 屬性 (Attribute) 也有 NameNamespace 屬性 (Property)。

  • 在未套用 CollectionDataContractAttribute 屬性時,集合型別的預設名稱和命名空間 (Namespace) 會取決於集合內所包含型別的名稱和命名空間。它們都不會被集合型別本身的名稱和命名空間影響。如需範例,請參閱下列型別。

    public CustomerList1 : Collection<string> {}
    public StringList1 : Collection<string> {}
    

這兩個型別的資料合約名稱都是 "ArrayOfstring",而不是 "CustomerList1" 或 "StringList1"。這表示在根層級序列化其中任何一個型別時,都會產生與下列程式碼相似的 XML。

<ArrayOfstring>
    <string>…</string>
    <string>…</string>
    <string>…</string>
    …
</ArrayOfstring>

選擇這個命名規則的原因,在於要確保表示字串清單的任何非自訂型別都具有相同的資料合約與 XML 表示。這樣集合便可進行互換。在此範例中,CustomerList1 和 StringList1 完全可以互換。

不過,當套用 CollectionDataContractAttribute 屬性 (Attribute) 時,集合會成為自訂的集合資料合約,即使未在此屬性上設定任何屬性 (Property) 也是如此。這樣一來,集合資料合約的名稱與命名空間便會取決於集合型別本身。如需範例,請參閱下列型別。

在經過序列化之後,會產生與下列相似的 XML。

<CustomerList2>
    <string>…</string>
    <string>…</string>
    <string>…</string>
    …
</CustomerList2>

請注意,這種 XML 已經不再相同於非自訂化型別的 XML 表示。

  • 您可以使用 NameNamespace 屬性來進一步自訂命名。請參閱下列類別。

產生的 XML 與下列程式碼相似。

<cust_list>
    <string>…</string>
    <string>…</string>
    <string>…</string>
    …
</cust_list>

如需詳細資訊,請參閱 本主題稍後的「進階集合規則」一節。

自訂清單集合中的重複項目名稱

清單集合包含一些重複的項目。通常,每個重複項目都會以項目表示,該項目會根據集合內所包含型別的資料合約名稱來命名。

CustomerList 範例中,集合包含的是字串。該字串基本型別 (Primitive Type) 的資料合約名稱為 "string",因此重複項目會是 "<string>"。

不過,只要在 CollectionDataContractAttribute 屬性 (Attribute) 上使用 ItemName 屬性 (Property),即可自訂這個重複項目。如需範例,請參閱下列型別。

產生的 XML 與下列程式碼相似。

<CustomerList4>
    <customer>…</ customer>
    <customer>…</customer>
    <customer>…</customer>
    …
</CustomerList4>

重複項目的命名空間永遠都會與集合資料合約的命名空間相同,而就像先前所述,使用 Namespace 屬性便可自訂此命名空間。

自訂字典集合

字典集合基本上就是項目清單,其中的每個項目都有後接一個值的索引鍵。就像是在使用一般清單,您可以使用 ItemName 屬性來變更重複項目的對應項目名稱。

此外,您也可以使用 KeyNameValueName 屬性來變更表示索引鍵與值的項目名稱。這些項目的命名空間都與集合資料合約的命名空間相同。

如需範例,請參閱下列型別。

在經過序列化之後,會產生與下列相似的 XML。

<CountriesOrRegionsWithCapitals>
    <entry>
        <countryorregion>USA</countryorregion>
        <capital>Washington</capital>
    </entry>
    <entry>
        <countryorregion>France</countryorregion>
        <capital>Paris</capital>
    </entry>
    …
</CountriesOrRegionsWithCapitals>

如需 字典集合的詳細資訊,請參閱本主題稍後的「進階集合規則」一節。

集合與已知型別

當使用多型方式,將集合取代其他集合或集合介面時,您並不需要將集合型別新增到已知型別中。例如,如果您宣告 IEnumerable 型別的資料成員,並使用該成員傳送 ArrayList 的執行個體,這時您並不需要將 ArrayList 新增到已知型別。

當您以多型方式使用集合來取代非集合型別時,這些集合就必須加入至已知型別中。例如,如果您宣告 Object 型別的資料成員,並使用該成員來傳送 ArrayList 的執行個體,請將 ArrayList 加入至已知型別。

這時您無法以多型方式來序列化任何相等的集合。例如,在上一個範例中,當您將 ArrayList 加入至已知型別清單時,這樣無法讓您指派 Array of Object 類別,即使此類別具有相等的資料合約也是如此。這點與非集合型別進行序列化時的一般已知型別行為並無不同,但是由於集合經常都是相等的,因此最好特別弄清楚這樣對集合而言的意義為何。

在序列化期間,任何資料合約的任何範圍中只能有一個已知的型別,而且相等的集合都會具有相同的資料合約。這表示在先前的範例中,您不可以將 ArrayListArray of Object 同時加入至相同範圍中的已知型別。同樣地,這個行為相同於非集合型別的已知型別行為,但是您要特別弄清楚這樣對於集合的意義為何。

集合的內容也可能需要已知型別。例如,如果實際上 ArrayList 是包含 Type1Type2 的執行個體,這兩個型別就應該要同時新增到已知型別。

下列範例會示範使用集合與已知型別而正確建構的物件圖形。這個範例有點不自然,因為在實際的應用程式中,您通常不會將下列資料成員定義為 Object,並因此不會有任何已知型別/多型問題。

在進行還原序列化時,如果宣告的型別是集合型別,則無論實際傳送的型別為何,這個已宣告型別都會完成具現化。如果宣告的型別是集合介面,還原序列化程式就會挑選要具現化的型別而不管已知型別為何。

另外,在還原序列化期間,如果宣告的型別不是集合型別,但是正在傳送的卻是某個集合型別,這時會從已知型別清單中挑選符合的集合型別。您也可以在進行還原序列化時,將集合介面型別新增到已知型別的清單中。同樣地,在此情況下,還原序列化引擎會挑選要具現化的型別。

集合與 NetDataContractSerializer 類別

當使用 NetDataContractSerializer 類別時,不是陣列的非自訂化集合型別 (不含 CollectionDataContractAttribute 屬性) 會失去其特殊意義。

已標示 SerializableAttribute 屬性的非自訂化集合型別,依然可由 NetDataContractSerializer 類別根據 SerializableAttribute 屬性或 ISerializable 介面規則加以序列化。

即使此時是使用 NetDataContractSerializer 類別,自訂的集合型別、集合介面及陣列依然會被視為集合。

集合與結構描述

所有相等的集合都具有相同的 XML 結構描述定義語言 (XSD) 結構描述表示方式。基於這點,通常您由所產生用戶端程式碼所取得的集合型別,並不相同於伺服器上的集合型別。例如,伺服器可能會搭配使用資料合約與整數資料成員的泛型 List,但是在產生的用戶端程式碼中,該相同資料成員可能會成為整數陣列。

字典集合都會以 WCF 特定結構描述附註標示,以表示這些集合是字典。否則,將無法區別這些集合與包含有索引鍵與值之項目的簡單清單。如需集合透過資料合約結構描述之表示方式的詳細描述,請參閱資料合約結構描述參考

根據預設,不會針對已匯入程式碼中的非自訂集合產生型別。清單集合型別的資料成員都會當做陣列匯入,而字典集合型別的資料成員會當做泛型字典匯入。

不過,對於自訂集合則會產生個別的型別,並標示 CollectionDataContractAttribute 屬性。(採用結構描述的自訂集合型別,就是不使用預設命名空間、名稱、重複項目名稱或索引鍵/值項目名稱的型別)。這些型別是從清單型別的泛型 List 或是字典型別的泛型字典所衍生的空型別。

例如,您在伺服器上可能擁有下列型別。

當匯出結構描述並再度將其匯入時,會產生與下列類似的用戶端程式碼 (此時顯示欄位而非屬性以提高可讀性)。

您可能希望使用所產生程式碼中的不同型別,而不要使用預設的型別。例如,您可能希望對資料成員使用泛型 BindingList 而不要使用一般陣列,以便更輕鬆地將成員繫結至使用者介面元件。

若要選擇要產生的集合型別,請在匯入結構描述時,將您要使用的集合型別清單傳入 ImportOptions 物件的 ReferencedCollectionTypes 屬性。這些型別稱為「參照集合型別」(Referenced Collection Type)。

如果是要參考泛型型別,這些型別必須是完全開放式的泛型,或是完全封閉式的泛型。

Aa347850.note(zh-tw,VS.90).gif注意:
當使用 Svcutil.exe 工具時,即可使用 /collectionType 命令列參數完成這項參考作業 (簡短形式:/ct)。請記住,您必須同時使用 /reference 參數 (簡短形式:/r) 來指定參照集合型別的組件 (Assembly)。如果該型別為泛型,後面就會接上反引號 (`) 與泛型參數的數目。請勿混淆反引號 (`) 與單引號 (‘) 字元。您可以多次使用 /collectionType 參數來指定多個參照集合型別。

例如,使所有清單都當做泛型 List 匯入。

svcutil.exe MyService.wsdl MyServiceSchema.xsd /r:C:\full_path_to_system_dll\System.dll /ct:System.Collections.Generic.List`1

匯入任何集合時,就會掃描這份參照集合型別清單,並且在找到一個型別時,將最符合的集合當做資料成員型別 (適用於非自訂集合) 來使用,或是當做要從其中衍生的基底型別 (Base Type) (適用於自訂集合)。字典只會與字典比對,清單也只會與清單比對。

例如,如果您將泛型 BindingListHashtable 新增到參考型別的清單,上述範例會產生與下列相似的用戶端程式碼。

您可以指定集合介面型別做為參照集合型別的一部分,不過您不能指定無效的集合型別 (例如沒有 Add 方法或公用建構函式的型別)。

封閉式泛型會被視為最符合的型別 (非泛型型別則會被視為相等於 Object 的封閉式泛型)。例如,如果 DateTime 的泛型 List、泛型 BindingList (開放式泛型) 和 ArrayList 都是參照集合型別,便會產生下列結果。

若是清單集合,則只支援下表中的清況。

參考型別 由參考型別實作的介面 範例 型別的處理方式:

非泛型或封閉式泛型 (任何參數數目)

非泛型

MyType : IList

MyType<T> : IList

其中 T= int

Object 的封閉式泛型 (例如,IList<object>)

非泛型或封閉式泛型 (任何數目之不需要符合集合型別的參數)

封閉式泛型

MyType : IList<string>

MyType<T> : IList<string> ,其中 T=int

封閉式泛型 (例如,IList<string>)

具有任何參數數目的封閉式泛型

使用型別之任何一個參數的開放式泛型

MyType<T,U,V> : IList<U>

其中 T=int,U=string,V=bool

封閉式泛型 (例如,IList<string>)

具有一個參數的開放式泛型

使用型別之參數的開放式泛型

MyType<T> : IList<T>,T 是開放式的

開放式泛型 (例如,IList<T>)

如果型別實作一個以上的清單集合介面,則會套用下列限制:

  • 如果型別針對不同型別多次實作泛型 IEnumerable (或其衍生的介面),該型別就不會被視為有效的參照集合型別,並將遭到忽略。即使其中一些實作為無效或是使用開放式泛型,也是如此。例如,實作 int 之泛型 IEnumerable 與 T 之泛型 IEnumerable 的型別一律不會當做 int 或任何其他型別的參照集合使用,無論該型別是否具有接受 intAdd 方法,或是具有接受型別 T 參數的 Add 方法。
  • 如果型別實作泛型集合介面和 IList,除非該泛型集合介面是型別 Object 的封閉式泛型,否則該型別永遠不會用來當做參照集合型別。

若是字典集合,則只支援下表中的清況。

參考型別 由參考型別實作的介面 範例 型別的處理方式

非泛型或封閉式泛型 (任何參數數目)

IDictionary

MyType : IDictionary

MyType<T> : IDictionary ,其中 T=int

封閉式泛型 IDictionary<object,object>

封閉式泛型 (任何參數數目)

IDictionary,封閉式

MyType<T> : IDictionary<string, bool> ,其中 T=int

封閉式泛型 (例如,IDIctionary<string,bool>)

封閉式泛型 (任何參數數目)

泛型 IDictionary,其中一個索引鍵或值屬封閉式,另一個則為開放式並使用型別的一個參數

MyType<T,U,V> : IDictionary<string,V>,其中 T=int,U=float,V=bool

MyType<Z> : IDictionary<Z,bool> ,其中 Z=string

封閉式泛型 (例如,IDictionary<string,bool>)

封閉式泛型 (任何參數數目)

泛型 IDictionary,索引鍵與值都屬開放式,而且每一個都會使用型別的一個參數

MyType<T,U,V> : IDictionary<V,U>,其中 T=int,U=bool,V=string

封閉式泛型 (例如,IDictionary<string,bool>)

開放式泛型 (兩個參數)

泛型 IDictionary,開放式,依照型別之泛型參數的出現順序來同時使用這兩個參數

MyType<K,V> : IDictionary<K,V>,K 與 V 都屬開放式

開放式泛型 (例如,IDictionary<K,V>)

如果型別同時實作 IDictionary 與泛型 IDictionary,這時就只會考慮泛型 IDictionary

不支援參考部分的泛型型別。

不允許重複。例如,您不能將 Integer 的泛型 ListInteger 的泛型集合同時加入至 ReferencedCollectionTypes,否則會造成當結構描述中出現整數清單時無法判斷要使用哪一個集合的問題。只有當結構描述中有公開重複問題的型別時,才會偵測到重複。例如,如果要匯入的結構描述不包含整數的清單,才能允許將 Integer 的泛型 ListInteger 的泛型集合新增到 ReferencedCollectionTypes,不過沒有一個會具有作用。

進階集合規則

序列化集合

下面是序列化之集合規則的清單:

  • 允許結合集合型別 (即新增集合的集合)。不規則陣列會被視為集合的集合。不支援多維陣列。
  • 位元組的陣列與 XmlNode 的陣列,都是會被視為基本型別 (而非集合) 的特殊陣列型別。序列化位元組陣列時會產生單一的 XML 項目 (其中包含 Base64 編碼資料區塊),而不是針對各個位元組產生個別項目。如需 如何處理 XmlNode 陣列的詳細資訊,請參閱資料合約中的 XML 與 ADO.NET 型別。當然,這些特殊型別本身可以參與集合:位元組陣列的陣列會產生多個 XML 項目,其中每個項目會包含 Base64 編碼資料的區塊。
  • 如果集合型別套用了 DataContractAttribute 屬性,該型別就會被視為一般資料合約類型,而不是集合。
  • 如果集合型別實作 IXmlSerializable 介面,則會套用下列規則,並指型別為 myType:IList<string>, IXmlSerializable
    • 如果宣告的型別為 IList<string>,則型別會序列化為清單。
    • 如果宣告的型別為 myType,它會序列化為 IXmlSerializable
    • 如果宣告的型別為 IXmlSerializable,則它會序列化為 IXmlSerializable,但只有在您將 myType 新增至已知型別的清單中才會這麼做。
  • 集合會透過下表中的方法來加以序列化與還原序列化。
實作的集合型別 進行序列化時呼叫的方法 進行還原序列化時呼叫的方法

泛型 IDictionary

get_Keys, get_Values

泛型 Add

IDictionary

get_Keys, get_Values

Add

泛型 IList

泛型 IList 索引子

泛型 Add

泛型 ICollection

列舉值

泛型 Add

IList

IList 索引子

Add

泛型 IEnumerable

GetEnumerator

稱為 Add 的非靜態方法,其會接受一個適當型別 (泛型參數型別或是它的一個基底型別) 的參數。序列化程式必須配合這種方法,才能在進行序列化與還原序列化時將集合型別視為集合來處理。

IEnumerable (以及衍生自該項的 ICollection)

GetEnumerator

稱為 Add 的非靜態方法,其會接受一個型別為 Object 的參數。序列化程式必須配合這種方法,才能在進行序列化與還原序列化時將集合型別視為集合來處理。

上面表格是依遞減的優先順序來列出集合介面。這表示,如果型別同時實作 IList 與泛型 IEnumerable,該集合便會根據 IList 規則完成序列化與還原序列化:

  • 在進行還原序列化時,所有集合在進行還原序列化時,都會先透過呼叫預設建構函式來建立該型別的執行個體,而序列化程式一定要配合此預設建構函式,才能在進行序列化與還原序列化時將集合型別視為集合來處理。
  • 如果超過一次地實作相同的泛型集合介面 (例如,如果型別同時實作 Integer 的泛型 ICollectionString 的泛型 ICollection),而且找不到較高優先順序的介面,這時集合就無法被視為有效的集合。
  • 這些集合型別都可以將 SerializableAttribute 屬性套用到本身,而且可以實作 ISerializable 介面。這兩者都會遭到忽略。不過,如果型別沒有完全符合集合型別需求 (例如,遺失了 Add 方法),該型別就不會被視為集合型別,而且這樣一來,SerializableAttribute 屬性與 ISerializable 介面就會用來判斷型別是否可序列化。
  • CollectionDataContractAttribute 屬性套用至集合以自訂集合時,會移除上述的 SerializableAttribute 後援機制。相反地,如果自訂的集合未能符合集合型別需求,便會擲回 InvalidDataContractException 例外狀況 (Exception)。例外狀況字串通常會包含資訊,說明指定型別為何未被視為有效的集合 (沒有 Add 方法、沒有預設建構函式,以及其他原因),因此通常為偵錯目的而套用 CollectionDataContractAttribute 屬性的做法會很有用。

集合命名

下面是集合命名規則的清單:

  • 除非已使用 Namespace 覆寫,否則所有字典集合資料合約以及包含基本型別之清單集合資料合約的預設命名空間,都會是 https://schemas.microsoft.com/2003/10/Serialization/Arrays。對應至內建 XSD 型別,以及 charTimespanGuid 型別的型別,都會因此目的而被視為基本型別。
  • 除非已使用 Namespace 覆寫,否則包含非基本型別之集合型別的預設命名空間,就是集合中所包含之型別的資料合約命名空間。
  • 除非已使用 Name 覆寫,否則清單集合資料合約的預設名稱,就會是 "ArrayOf" 字串與集合中所包含型別之資料合約名稱的組合。例如,整數泛型清單的資料合約名稱是 "ArrayOfint"。請記住,Object 的資料合約名稱是 "anyType",因此非泛型清單 (例如,ArrayList) 的資料合約名稱會是 "ArrayOfanyType"。

除非已使用 Name 覆寫,否則字典集合資料合約的預設名稱,就會是 "ArrayOfKeyValueOf" 字串與索引鍵型別之資料合約名稱加上值型別之資料合約名稱的組合。例如,字串與整數之泛型字典的資料合約名稱為 "ArrayOfKeyValueOfstringint"。此外,如果索引鍵或值型別其中一個不是基本型別,便會在名稱後附加索引鍵與值型別之資料合約命名空間的命名空間雜湊。如需 命名空間雜湊的詳細資訊,請參閱資料合約名稱

每個字典集合資料合約都具有表示字典中一個項目的附屬資料合約。除了 "ArrayOf" 的前置詞以外,該合約的名稱與字典資料合約的名稱相同,而且其命名空間也與字典資料合約相同。例如,對於 "ArrayOfKeyValueOfstringint" 字典資料合約,"KeyValueofstringint" 資料合約表示字典中的一個項目。您可以使用 ItemName 屬性來自訂這個資料合約的名稱,如下節所示。

資料合約名稱中所述,泛型型別命名規則會完全套用到集合型別,也就是說,您可以在名稱內使用大括號來表示泛型型別參數。不過,在大括號內的數字是指泛型參數數目,而非集合內所包含型別的數目。

集合自訂化

禁止以下列方式使用 CollectionDataContractAttribute 屬性,否則會造成 InvalidDataContractException 例外狀況:

  • DataContractAttribute 屬性套用至已套用 CollectionDataContractAttribute 屬性的型別,或是套用至它的一個衍生型別。
  • CollectionDataContractAttribute 屬性套用至實作 IXmlSerializable 介面的型別。
  • CollectionDataContractAttribute 屬性套用至非集合型別。
  • 嘗試在已套用至非字典型別的 CollectionDataContractAttribute 屬性上設定 KeyNameValueName

多型規則

正如先前所述,使用 CollectionDataContractAttribute 屬性來自訂集合可能會干擾集合的可互換性。唯有兩個自訂集合型別的名稱、命名空間、項目名稱,以及索引鍵與值名稱 (如果是字典集合) 彼此相符時,這兩個集合型别才能被視為相等。

由於自訂化的關係,有可能會發生應該使用某個集合資料合約,但卻不慎使用另一個集合資料合約的情形。對此應該要設法避免。請參閱下列型別。

在此範例中,Marks1 的執行個體可以指派到 testMarks。但是,不應使用 Marks2,因為其資料合約不被視為相等於 IList<int> 資料合約。資料合約名稱是 "Marks2" 而非 "ArrayOfint",而且重複項目名稱是 "<mark>" 而非 "<int>"。

下表中的規則適用於集合的多型指派。

宣告的型別 指派非自訂的集合 指派自訂的集合

物件

合約名稱已經序列化。

合約名稱已經序列化。

已使用自訂。

集合介面

合約名稱未序列化。

合約名稱未序列化。

未使用自訂。*

非自訂的集合

合約名稱未序列化。

合約名稱已經序列化。

已使用自訂。**

自訂的集合

合約名稱已經序列化。未使用自訂。**

合約名稱已經序列化。

已使用所指派型別的自訂。**

*在此情況下是透過 NetDataContractSerializer 類別來使用自訂。在此情況下,NetDataContractSerializer 類別也會序列化實際的型別名稱,以便讓還原序列化如預期地運作。

**這些情況會產生結構描述無效的執行個體,因此應該盡量避免。

在合約名稱已經序列化的情況下,所指派的集合型別應該會在已知型別的清單中。反之亦然:因為在名稱未經序列化的情況下,並不需要將型別加入至已知型別清單中。

衍生型別的陣列可以指派給基底型別的陣列。在此情況下,衍生型別的合約名稱會針對每個重複項目加以序列化。例如,如果型別 Book 是衍生自型別 LibraryItem,您就可以將 Book 的陣列指派到 LibraryItem 的陣列。這點並不適用於其他集合型別。例如,您無法將 Generic List of Book 指派到 Generic List of LibraryItem。不過,您可以指派包含 Book 執行個體的 Generic List of LibraryItem。在陣列與非陣列的兩種情況下,Book 都應該會在已知型別清單中。

集合與物件參考保留

當序列化程式在保留物件參考的模式下運作時,物件參考保留也會套用到集合。具體來說,就是整個集合與集合中所包含的個別項目都會保留其物件身分識別。若是字典,則會針對索引鍵/值組物件以及個別的索引鍵和值物件保留物件身分識別。

請參閱

參考

CollectionDataContractAttribute