Enumeration Types in Data Contracts
Enumerations can be expressed in the data contract model. This topic walks through several examples that explain the programming model.
One way to use enumeration types in the data contract model is to apply the DataContractAttribute attribute to the type. You must then apply the EnumMemberAttribute attribute to each member that must be included in the data contract.
The following example shows two classes. The first uses the enumeration and the second defines the enumeration.
<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
An instance of the Car class can be sent or received only if the condition field is set to one of the values New, Used, or Rental. If the condition is Broken or Stolen, a SerializationException is thrown.
Generally the data contract includes enumeration member names, not numerical values. However, when using the data contract model, if the receiving side is a WCF client, the exported schema preserves the numerical values. Note that this is not the case when using the Using the XmlSerializer Class.
In the preceding example, if condition is set to Used and the data is serialized to XML, the resulting XML is <condition>Used</condition> and not <condition>1</condition>. Therefore, the following data contract is equivalent to the data contract of CarConditionEnum.
<DataContract(Name := "CarCondition")> _ Public Enum CarConditionWithNumbers <EnumMember> NewCar = 10 <EnumMember> Used = 20 <EnumMember> Rental = 30 End Enum
For example, you can use CarConditionEnum on the sending side and CarConditionWithNumbers on the receiving side. Although the sending side uses the value "1" for Used and the receiving side uses the value "20," the XML representation is <condition>Used</condition> for both sides.
To be included in the data contract, you must apply the EnumMemberAttribute attribute. In the .NET Framework, you can always apply the special value 0 (zero) to an enumeration, which is also the default value for any enumeration. However, even this special zero value cannot be serialized unless it is marked with the EnumMemberAttribute attribute.
There are two exceptions to this:
Flag enumerations (discussed later in this topic).
Enumeration data members with the EmitDefaultValue property set to false (in which case, the enumeration with the value zero is omitted from the serialized data).
For example, the following data contract is also equivalent to the data contract of the CarConditionEnum.
<DataContract(Name := "CarCondition")> _ Public Enum CarConditionWithDifferentNames <EnumMember(Value := "New")> BrandNew <EnumMember(Value := "Used")>PreviouslyOwned <EnumMember> Rental End Enum
When serialized, the value of PreviouslyOwned has the XML representation <condition>Used</condition>.
You can also serialize enumeration types to which the DataContractAttribute attribute has not been applied. Such enumeration types are treated exactly as previously described, except that every member (that does not have the NonSerializedAttribute attribute applied) is treated as if the EnumMemberAttribute attribute has been applied. For example, the following enumeration implicitly has a data contract equivalent to the preceding CarConditionEnum example.
You can use simple enumerations when you do not need to customize the enumeration's data contract name and namespace and the enumeration member values.
Applying the EnumMemberAttribute attribute to simple enumerations has no effect.
It makes no difference whether or not the SerializableAttribute attribute is applied to the enumeration.
The fact that the DataContractSerializer class honors the NonSerializedAttribute attribute applied to enumeration members is different from the behavior of the BinaryFormatter and the SoapFormatter. Both of those serializers ignore the NonSerializedAttribute attribute.
You can apply the FlagsAttribute attribute to enumerations. In that case, a list of zero or more enumeration values can be sent or received simultaneously.
To do so, apply the DataContractAttribute attribute to the flag enumeration and then mark all the members that are powers of two with the EnumMemberAttribute attribute. Note that to use a flag enumeration, the progression must be an uninterrupted sequence of powers of 2 (for example, 1, 2, 4, 8, 16, 32, 64).
The following steps apply to sending a flag's enumeration value:
Attempt to find an enumeration member (with the EnumMemberAttribute attribute applied) that maps to the numeric value. If found, send a list that contains just that member.
Attempt to break the numeric value into a sum such that there are enumeration members (each with the EnumMemberAttribute attribute applied) that map to each part of the sum. Send the list of all these members. Note that the greedy algorithm is used to find such a sum, and thus there is no guarantee that such a sum is found even if it is present. To avoid this problem, make sure that the numeric values of the enumeration members are powers of two.
If the preceding two steps fail, and the numeric value is nonzero, throw a SerializationException. If the numeric value is zero, send the empty list.
The following enumeration example can be used in a flag operation.
<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
The following example values are serialized as indicated.
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.