Bagikan melalui


Jenis Enumerasi dalam Kontrak Data

Enumerasi dapat diekspresikan dalam model kontrak data. Topik ini membahas beberapa contoh yang menjelaskan model pemrograman.

Dasar-Dasar Enumerasi

Salah satu cara untuk menggunakan jenis enumerasi dalam model kontrak data adalah dengan menerapkan atribut DataContractAttribute ke jenis. Kemudian Anda harus menerapkan atribut EnumMemberAttribute ke setiap anggota yang harus disertakan dalam kontrak data.

Contoh berikut menunjukkan dua kelas. Yang pertama menggunakan enumerasi dan yang kedua mendefinisikan enumerasi.

[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

Instans kelas Car dapat dikirim atau diterima hanya jika bidang condition ditetapkan ke salah satu nilai New, Used, atau Rental. Jika condition adalah Broken atau Stolen, SerializationException akan dilempar.

Anda dapat menggunakan properti DataContractAttribute (Name dan Namespace) seperti biasa untuk kontrak data enumerasi.

Nilai Anggota Enumerasi

Umumnya kontrak data mencakup nama anggota enumerasi, bukan nilai numerik. Namun, saat menggunakan model kontrak data, jika pihak penerima adalah klien WCF, skema yang diekspor mempertahankan nilai numerik. Perhatikan bahwa hal ini tidak terjadi saat menggunakan Menggunakan Kelas XmlSerializer.

Pada contoh sebelumnya, jika condition ditetapkan ke Used dan data diserialisasikan ke XML, XML yang dihasilkan adalah <condition>Used</condition> dan bukan <condition>1</condition>. Oleh karena itu, kontrak data berikut setara dengan kontrak data 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

Misalnya, Anda dapat menggunakan CarConditionEnum di sisi pengiriman dan CarConditionWithNumbers di sisi penerimaan. Meskipun sisi pengiriman menggunakan nilai "1" untuk Used dan sisi penerimaan menggunakan nilai "20," representasi XML-nya adalah <condition>Used</condition> untuk kedua sisi.

Agar disertakan dalam kontrak data, Anda harus menerapkan atribut EnumMemberAttribute. Dalam .NET Framework, Anda selalu dapat menerapkan nilai khusus 0 (nol) ke enumerasi, yang juga merupakan nilai default untuk enumerasi apa pun. Namun, bahkan nilai nol khusus ini tidak dapat diserialisasikan kecuali jika ditandai dengan atribut EnumMemberAttribute.

Ada dua pengecualian untuk ini:

  • Enumerasi bendera (dibahas nanti dalam topik ini).

  • Anggota data enumerasi dengan properti EmitDefaultValue ditetapkan ke false (dalam hal ini, enumerasi dengan nilai nol dihilangkan dari data yang diserialisasikan).

Menyesuaikan Nilai Anggota Enumerasi

Anda dapat menyesuaikan nilai anggota enumerasi yang membentuk bagian dari kontrak data menggunakan properti Value dari atribut EnumMemberAttribute.

Misalnya, kontrak data berikut juga setara dengan kontrak data 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

Setelah diserialisasikan, nilai PreviouslyOwned memiliki representasi XML <condition>Used</condition>.

Enumerasi Sederhana

Anda juga dapat menserialisasikan jenis enumerasi yang atribut DataContractAttribute-nya belum diterapkan. Jenis enumerasi tersebut diperlakukan seperti yang dijelaskan sebelumnya, kecuali bahwa setiap anggota (yang tidak memiliki atribut NonSerializedAttribute yang diterapkan) diperlakukan seolah-olah atribut EnumMemberAttribute telah diterapkan. Misalnya, enumerasi berikut secara implisit memiliki kontrak data yang setara dengan contoh CarConditionEnum sebelumnya.

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

Anda dapat menggunakan enumerasi sederhana saat Anda tidak perlu menyesuaikan namespace layanan dan nama kontrak data enumerasi serta nilai anggota enumerasi.

Catatan tentang Enumerasi Sederhana

Menerapkan atribut EnumMemberAttribute ke enumerasi sederhana tidak berpengaruh.

Ini tidak ada bedanya apakah atribut SerializableAttribute diterapkan ke enumerasi atau tidak.

Fakta bahwa kelas DataContractSerializer menghormati atribut NonSerializedAttribute yang diterapkan ke anggota enumerasi berbeda dengan perilaku BinaryFormatter dan SoapFormatter. Kedua serializer tersebut mengabaikan atribut NonSerializedAttribute.

Enumerasi Bendera

Anda dapat menerapkan atribut FlagsAttribute ke enumerasi. Dalam hal tersebut, daftar nilai enumerasi nol atau lebih dapat dikirim atau diterima secara bersamaan.

Untuk melakukannya, terapkan atribut DataContractAttribute ke enumerasi bendera lalu tandai semua anggota yang merupakan pangkat dua dengan atribut EnumMemberAttribute. Perhatikan bahwa untuk menggunakan enumerasi bendera, deretnya harus merupakan urutan pangkat 2 (misalnya, 1, 2, 4, 8, 16, 32, 64).

Langkah-langkah berikut berlaku untuk mengirim nilai enumerasi bendera:

  1. Coba temukan anggota enumerasi (dengan atribut EnumMemberAttribute diterapkan) yang memetakan ke nilai numerik. Jika ditemukan, kirim daftar yang hanya berisi anggota tersebut.

  2. Cobalah untuk memecah nilai numerik menjadi jumlah sehingga ada anggota enumerasi (masing-masing dengan atribut EnumMemberAttribute diterapkan) yang memetakan ke setiap bagian dari jumlah tersebut. Kirim daftar semua anggota ini. Perhatikan bahwa algoritma greedy digunakan untuk menemukan jumlah seperti itu, dan dengan demikian tidak ada jaminan bahwa jumlah tersebut ditemukan meskipun ada. Untuk menghindari masalah ini, pastikan bahwa nilai numerik dari anggota enumerasi adalah pangkat dua.

  3. Jika dua langkah sebelumnya gagal, dan nilai numerik bukan nol, lemparkan SerializationException. Jika nilai numerik nol, kirim daftar kosong.

Contoh

Contoh enumerasi berikut dapat digunakan pada operasi bendera.

[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

Nilai contoh beriku diserialisasikan seperti yang ditunjukkan.

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.

Lihat juga