열거형은 데이터 계약 모델에서 표현할 수 있습니다. 이 항목에서는 프로그래밍 모델을 설명하는 몇 가지 예제를 안내합니다.
열거형 기본 사항
데이터 계약 모델에서 열거형 형식을 사용하는 한 가지 방법은 형식에 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이(가) throw됩니다.
열거형 데이터 계약에는 평소와 같이 속성(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" Used 값을 사용하고 수신 쪽에서 값 "20"을 사용하지만 XML 표현은 <condition>Used</condition> 양쪽 모두에 사용됩니다.
데이터 계약에 포함하려면 특성을 적용 EnumMemberAttribute 해야 합니다. .NET Framework에서 항상 열거형에 특수 값 0(0)을 적용할 수 있습니다. 이 값은 열거형의 기본값이기도 합니다. 그러나 EnumMemberAttribute 속성으로 표시되지 않는 한 이 특수 0 값도 직렬화할 수 없습니다.
여기에는 두 가지 예외가 있습니다.
플래그 열거형(이 항목에서 나중에 논의됨).
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 나누려고 시도합니다. 이러한 모든 멤버의 목록을 보냅니다. greedy 알고리즘은 이러한 합계를 찾는 데 사용되므로 그러한 합계가 있는 경우에도 이러한 합계를 찾을 수 있다는 보장은 없습니다. 이 문제를 방지하려면 열거형 멤버의 숫자 값이 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.