列挙型は、データ コントラクト モデルで表すことができます。 このトピックでは、プログラミング モデルについて説明するいくつかの例について説明します。
列挙の基本
データ コントラクト モデルで列挙型を使用する 1 つの方法は、 DataContractAttribute 属性を型に適用することです。 その後、データ コントラクトに含める必要がある各メンバーに EnumMemberAttribute 属性を適用する必要があります。
次の例は、2 つのクラスを示しています。 1 つ目は列挙型を使用し、2 つ目は列挙型を定義します。
[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 を使用できます。 送信側では Used に値 "1" を使用し、受信側では値 "20" を使用しますが、XML 表現は両側に <condition>Used</condition> 。
データ コントラクトに含めるには、 EnumMemberAttribute 属性を適用する必要があります。 .NET Framework では、特別な値 0 (ゼロ) を列挙体に常に適用できます。これは、任意の列挙の既定値でもあります。 ただし、この特殊なゼロ値であっても、 EnumMemberAttribute 属性でマークされていない限り、シリアル化できません。
これには 2 つの例外があります。
フラグ列挙体 (このトピックで後述)。
EmitDefaultValue プロパティが
falseに設定されている列挙データ メンバー (この場合、値 0 の列挙はシリアル化されたデータから省略されます)。
列挙メンバー値のカスタマイズ
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属性を列挙型に適用できます。 その場合、0 個以上の列挙値のリストを同時に送受信できます。
これを行うには、フラグ列挙に DataContractAttribute 属性を適用し、2 の累乗であるすべてのメンバーを EnumMemberAttribute 属性でマークします。 フラグ列挙体を使用するには、進行は 2 の累乗の中断のないシーケンスである必要があります (例: 1、2、4、8、16、32、64)。
フラグの列挙値の送信には、次の手順が適用されます。
数値にマップされる列挙メンバー ( EnumMemberAttribute 属性が適用されている) を検索します。 見つかった場合は、そのメンバーのみを含むリストを送信します。
合計の各部にマップされる列挙メンバー (それぞれに EnumMemberAttribute 属性が適用されている) が存在するような形で、数値をこの合計に分割します。 これらすべてのメンバーの一覧を送信します。 このような合計を検索するために 最長一致アルゴリズム が使用されるため、存在する場合でもそのような合計が見つかるという保証はありません。 この問題を回避するには、列挙メンバーの数値が 2 の累乗であることを確認します。
上記の 2 つの手順が失敗し、数値が 0 以外の場合は、 SerializationExceptionをスローします。 数値が 0 の場合は、空のリストを送信します。
例
フラグ操作では、次の列挙例を使用できます。
[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.