枚舉可以在資料契約模型中表示。 本主題會逐步解說數個說明程序設計模型的範例。
列舉基本概念
在數據合約模型中使用列舉型別的其中一種方法是將 DataContractAttribute 屬性套用至型別。 然後,您必須將 EnumMemberAttribute 屬性套用至數據合約中必須包含的每個成員。
下列範例顯示兩個類別。 第一個使用列舉,第二個定義列舉。
[DataContract]
public class Car
{
[DataMember]
public string model;
[DataMember]
public CarConditionEnum condition;
}
[DataContract(Name = "CarCondition")]
public enum CarConditionEnum
{
[EnumMember]
New,
[EnumMember]
Used,
[EnumMember]
Rental,
Broken,
Stolen
}
<DataContract()> _
Public Class Car
<DataMember()> _
Public model As String
<DataMember()> _
Public condition As CarConditionEnum
End Class
<DataContract(Name:="CarCondition")> _
Public Enum CarConditionEnum
<EnumMember> NewCar
<EnumMember> Used
<EnumMember> Rental
Broken
Stolen
End Enum
只有在Car欄位設定為condition、New或Used其中一個值時,才可以傳送或接收Rental類別的實例。 若condition為Broken或Stolen,則會拋出SerializationException。
您可以像往常一樣使用 DataContractAttribute 屬性 (Name 和 Namespace) 來列舉數據合約。
列舉成員值
一般而言,數據合約包含列舉成員名稱,而非數值。 不過,使用數據合約模型時,如果接收端是WCF用戶端,則導出的架構會保留數值。 請注意,使用 XmlSerializer 類別 時,情況並非如此。
在上述範例中,如果 condition 設定為 Used ,且數據串行化為 XML,則產生的 XML 為 <condition>Used</condition> ,而不是 <condition>1</condition>。 因此,下列數據合約相當於 的數據合約 CarConditionEnum。
[DataContract(Name = "CarCondition")]
public enum CarConditionWithNumbers
{
[EnumMember]
New = 10,
[EnumMember]
Used = 20,
[EnumMember]
Rental = 30,
}
<DataContract(Name:="CarCondition")> _
Public Enum CarConditionWithNumbers
<EnumMember> NewCar = 10
<EnumMember> Used = 20
<EnumMember> Rental = 30
End Enum
例如,您可以在傳送端使用CarConditionEnum,在接收端使用CarConditionWithNumbers。 雖然傳送端使用值「1」,接收端使用值「20」,但 XML 表示在兩端均為 Used。
若要包含在資料合約中,您必須套用 EnumMemberAttribute 屬性。 在 .NET Framework 中,您一律可以將特殊值 0 (零) 套用至列舉,這也是任何列舉的預設值。 不過,即使這個特殊的零值也無法串行化,除非它以 EnumMemberAttribute 屬性標示。
有兩個例外狀況:
旗標列舉 (本主題稍後討論)。
列舉數據成員,其屬性設為 EmitDefaultValue 且其值為
false時,擁有值為零的列舉將不會包含在序列化數據中。
自定義列舉成員值
您可以使用 Value 屬性中的 EnumMemberAttribute 屬性,自定義作為數據合約一部分的列舉成員值。
例如,下列數據合約也相當於CarConditionEnum的數據合約。
[DataContract(Name = "CarCondition")]
public enum CarConditionWithDifferentNames
{
[EnumMember(Value = "New")]
BrandNew,
[EnumMember(Value = "Used")]
PreviouslyOwned,
[EnumMember]
Rental
}
<DataContract(Name:="CarCondition")> _
Public Enum CarConditionWithDifferentNames
<EnumMember(Value:="New")> BrandNew
<EnumMember(Value:="Used")> PreviouslyOwned
<EnumMember> Rental
End Enum
序列化時,的值 PreviouslyOwned 具有 XML 表示法 <condition>Used</condition>。
簡單列舉
您也可以序列化尚未套用DataContractAttribute屬性的列舉型別。 這類列舉型別的處理方式與先前所述完全相同,不同在於每個成員(未套用 NonSerializedAttribute 屬性的成員)將被視為已套用 EnumMemberAttribute 屬性。 例如,下列列舉會隱含地具有相當於上述 CarConditionEnum 範例的數據合約。
public enum CarCondition
{
New,
Used,
Rental,
[NonSerialized]
Lost
}
Public Enum CarCondition
[New]
Used
Rental
End Enum
當您不需要自定義列舉的數據合約名稱和命名空間和列舉成員值時,可以使用簡單的列舉。
簡單列舉的注意事項
將 EnumMemberAttribute 屬性套用至簡單列舉沒有任何作用。
不論屬性是否 SerializableAttribute 套用至 列舉,都沒有任何差異。
DataContractSerializer 類別接受套用到列舉成員的 NonSerializedAttribute 屬性,這與 BinaryFormatter 和 SoapFormatter 的行為不同。 這兩個串行化程序都會忽略 NonSerializedAttribute 屬性。
旗標列舉
您可以將 FlagsAttribute 屬性套用至列舉類型。 在此情況下,可以同時傳送或接收零個或多個列舉值的清單。
若要這樣做,請將 DataContractAttribute 屬性套用至旗標列舉,然後使用 EnumMemberAttribute 屬性標記所有是二的冪次方的成員。 請注意,若要使用旗標列舉,進展必須是 2 的不間斷權力序列(例如 1、2、4、8、16、32、64)。
下列步驟適用於旗標的列舉值之傳送:
嘗試尋找套用 EnumMemberAttribute 屬性的列舉成員,以對應至該數值。 如果找到,請傳送只包含該成員的清單。
嘗試將數值分成總和,使列舉成員(每一個成員都套用EnumMemberAttribute屬性)對應到總和的每一部分。 傳送所有這些成員的清單。 請注意,貪婪演算法 是用來尋找這類總和的,因此即使這樣的總和存在,也不能保證一定能找到。 若要避免這個問題,請確定列舉成員的數值是兩個的乘冪。
如果上述兩個步驟失敗,且數值為非零值,則擲回 SerializationException。 如果數值為零,請傳送空白清單。
範例
下列列舉範例可用於旗標作業。
[DataContract][Flags]
public enum CarFeatures
{
None = 0,
[EnumMember]
AirConditioner = 1,
[EnumMember]
AutomaticTransmission = 2,
[EnumMember]
PowerDoors = 4,
AlloyWheels = 8,
DeluxePackage = AirConditioner | AutomaticTransmission | PowerDoors | AlloyWheels,
[EnumMember]
CDPlayer = 16,
[EnumMember]
TapePlayer = 32,
MusicPackage = CDPlayer | TapePlayer,
[EnumMember]
Everything = DeluxePackage | MusicPackage
}
<DataContract(), Flags()> _
Public Enum CarFeatures
None = 0
<EnumMember> AirConditioner = 1
<EnumMember> AutomaticTransmission = 2
<EnumMember> PowerDoors = 4
AlloyWheels = 8
DeluxePackage = AirConditioner Or AutomaticTransmission Or PowerDoors Or AlloyWheels
<EnumMember> CDPlayer = 16
<EnumMember> TapePlayer = 32
MusicPackage = CDPlayer Or TapePlayer
<EnumMember> Everything = DeluxePackage Or MusicPackage
End Enum
下列範例值會依指示串行化。
CarFeatures cf1 = CarFeatures.AutomaticTransmission;
//Serialized as <cf1>AutomaticTransmission</cf1>
CarFeatures cf2 = (CarFeatures)5;
//Serialized as <cf2>AirConditioner PowerDoors</cf2> since 5=1+4
CarFeatures cf3 = CarFeatures.MusicPackage;
//Serialized as <cf3>CDPlayer TapePlayer</cf3> since MusicPackage itself is not an EnumMember
CarFeatures cf4 = CarFeatures.Everything;
//Serialized as <cf4>Everything</cf4> since Everything itself is an EnumMember
CarFeatures cf5 = CarFeatures.DeluxePackage;
//Throws a SerializationException since neither DeluxePackage nor AlloyWheels are EnumMembers
CarFeatures cf6 = CarFeatures.None;
//Serialized as the empty list <cf6></cf6> since there is no EnumMember mapped to zero
Private cf1 As CarFeatures = CarFeatures.AutomaticTransmission
'Serialized as <cf1>AutomaticTransmission</cf1>
Private cf2 As CarFeatures = ctype(5, CarFeatures)
'Serialized as <cf2>AirConditioner PowerDoors</cf2> since 5=1+4
Private cf3 As CarFeatures = CarFeatures.MusicPackage
'Serialized as <cf3>CDPlayer TapePlayer</cf3> since MusicPackage
' itself is not an EnumMember.
Private cf4 As CarFeatures = CarFeatures.Everything
'Serialized as <cf4>Everything</cf4> since Everything itself is an EnumMember.
Private cf5 As CarFeatures = CarFeatures.DeluxePackage
'Throws a SerializationException since neither DeluxePackage nor
' AlloyWheels are EnumMembers.
Private cf6 As CarFeatures = CarFeatures.None
'Serialized as the empty list <cf6></cf6> since there is no EnumMember mapped to zero.