Share via


데이터 계약의 열거형 형식

데이터 계약 모델에 열거형을 표현할 수 있습니다. 이 항목에서는 프로그래밍 모델을 설명하는 여러 예를 살펴봅니다.

열거형 기본 사항

데이터 계약 모델에 열거형 형식을 사용하는 방법 중 하나는 형식에 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 값 중 하나로 설정된 경우에만 보내고 받을 수 있습니다. conditionBroken 또는 Stolen이면 SerializationException이 throw됩니다.

열거형 데이터 계약에도 보통 때와 같이 DataContractAttribute 속성(NameNamespace)을 사용할 수 있습니다.

열거형 멤버 값

일반적으로 데이터 계약에는 숫자 값이 아닌 열거형 멤버 이름이 포함됩니다. 하지만 데이터 계약 모델을 사용하는 경우 받는 쪽이 WCF 클라이언트이면 내보낸 스키마에서 숫자 값을 유지합니다. XmlSerializer 클래스 사용을 사용할 때는 그렇지 않습니다.

앞의 예에서 conditionUsed로 설정되어 있고 데이터가 XML로 serialize된 경우 결과 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(영)을 적용할 수 있으며 이는 열거형의 기본값이기도 합니다. 하지만 이 특수 값 0도 EnumMemberAttribute 특성으로 표시하지 않으면 serialize할 수 없습니다.

여기에는 두 가지 예외 사항이 있습니다.

  • 플래그 열거형(이 항목의 뒷부분에서 설명).

  • EmitDefaultValue 속성이 false로 설정된 열거형 데이터 멤버. 이 경우 값이 0인 열거형은 serialize할 데이터에서 생략됩니다.

열거형 멤버 값 사용자 지정

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

serialize된 PreviouslyOwned 값의 XML 표현은 <condition>Used</condition>입니다.

단순 열거형

DataContractAttribute 특성이 적용되지 않은 열거형 형식을 serialize할 수도 있습니다. 그러한 열거형 형식은 위 설명과 완전히 같은 방식으로 취급되지만, NonSerializedAttribute 특성이 적용되지 않은 모든 멤버가 EnumMemberAttribute 특성이 적용된 것처럼 취급된다는 점이 다릅니다. 예를 들어, 다음 열거형에는 위의 CarConditionEnum 예제에 해당되는 데이터 계약이 암시적으로 존재합니다.

public enum CarCondition
{
    New,
    Used,
    Rental,
    [NonSerialized]
    Lost
}
Public Enum CarCondition
    [New]
    Used
    Rental
End Enum

열거형의 데이터 계약 이름 및 네임스페이스와 열거형 멤버 값을 사용자 지정할 필요가 없는 경우 단순 열거형을 사용할 수 있습니다.

단순 열거형에 대한 참고 사항

EnumMemberAttribute 특성을 단순 열거형에 적용해도 아무 영향이 없습니다.

SerializableAttribute 특성이 열거형에 적용되었는지 여부도 관계 없습니다.

DataContractSerializer 클래스에서 열거형 멤버에 적용된 NonSerializedAttribute 특성을 따른다는 점은 BinaryFormatterSoapFormatter의 동작과 다릅니다. 이 두 가지 serializer는 모두 NonSerializedAttribute 특성을 무시합니다.

플래그 열거형

FlagsAttribute 특성을 열거형에 적용할 수 있습니다. 이 경우 0개 이상의 열거형 값 목록을 동시에 보내거나 받을 수 있습니다.

그러려면 플래그 열거형에 DataContractAttribute 특성을 적용한 다음 2의 거듭제곱에 해당되는 모든 멤버를 EnumMemberAttribute 특성으로 표시합니다. 플래그 열거형을 사용하려면 2의 거듭제곱이 끊어지지 않고 순서대로 진행되어야 합니다(예: 1, 2, 4, 8, 16, 32, 64).

다음 단계는 플래그의 열거형 값을 보내는 경우에 적용됩니다.

  1. 숫자 값에 매핑되는 열거형 멤버를 찾아 봅니다(EnumMemberAttribute 특성 적용). 찾은 경우 해당 멤버만 포함하는 목록을 보냅니다.

  2. 합의 각 부분에 매핑되는 열거형 멤버가 있는(각각 EnumMemberAttribute 특성 적용) 숫자 값을 합으로 정리해 봅니다. 해당되는 모든 멤버의 목록을 보냅니다. 과대 알고리즘을 사용하여 그런 합을 찾기 때문에 그런 합이 있다고 해서 발견된다는 보장은 없습니다. 이 문제를 방지하려면 열거형 멤버의 숫자 값이 2의 거듭제곱이어야 합니다.

  3. 앞의 두 단계가 실패한 경우 숫자 값이 0이 아니면 SerializationException이 throw됩니다. 숫자 값이 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

다음 예제의 값은 표시된 대로 serialize됩니다.

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.

참고 항목