Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wyliczenia można wyrazić w modelu kontraktu danych. W tym temacie przedstawiono kilka przykładów wyjaśniających model programowania.
Podstawy wyliczenia
Jednym ze sposobów użycia typów wyliczenia w modelu kontraktu danych jest zastosowanie atrybutu DataContractAttribute do typu. Następnie należy zastosować atrybut EnumMemberAttribute do każdego członka, który musi zostać uwzględniony w kontrakcie danych.
W poniższym przykładzie przedstawiono dwie klasy. Pierwszy używa wyliczenia, a drugi definiuje wyliczenie.
[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
Wystąpienie Car
klasy można wysłać lub odebrać tylko wtedy, gdy condition
pole jest ustawione na jedną z wartości New
, Used
lub Rental
. Jeśli condition
to Broken
lub Stolen
, zostaje zgłoszony SerializationException.
Możesz używać właściwości DataContractAttribute (Name i Namespace) jak zwykle w przypadku kontraktów danych typu wyliczającego.
Wyliczenie wartości składowych
Ogólnie rzecz biorąc, kontrakt danych zawiera nazwy elementów członkowskich wyliczenia, a nie wartości liczbowe. Jednak w przypadku korzystania z modelu kontraktu danych, jeśli strona odbierania jest klientem WCF, wyeksportowany schemat zachowuje wartości liczbowe. Należy pamiętać, że nie jest tak w przypadku używania klasy XmlSerializer.
W poprzednim przykładzie, jeśli condition
jest ustawione na Used
i dane są zserializowane do XML, wynikowy XML to <condition>Used</condition>
, a nie <condition>1</condition>
. W związku z tym następujący kontrakt danych jest odpowiednikiem kontraktu danych 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
Na przykład można użyć CarConditionEnum
po stronie wysyłającej i CarConditionWithNumbers
po stronie odbierającej. Mimo że strona wysyłania używa wartości "1" dla Used
, a strona odbierania używa wartości "20", reprezentacja XML jest <condition>Used</condition>
dla obu stron.
Aby zostać uwzględnionym w umowie danych, należy zastosować atrybut EnumMemberAttribute. W programie .NET Framework zawsze można zastosować wartość specjalną 0 (zero) do wyliczenia, która jest również wartością domyślną dla dowolnego wyliczenia. Jednak nawet ta specjalna wartość zerowa nie może być serializowana, chyba że jest oznaczona atrybutem EnumMemberAttribute .
Istnieją dwa wyjątki:
Wyliczenia flag (omówione w dalszej części tego tematu).
Wyliczenie elementów członkowskich danych z właściwością EmitDefaultValue ustawioną na
false
(w tym przypadku wyliczenie z wartością zero zostanie pominięte z danych serializowanych).
Dostosowywanie wartości składowych wyliczenia
Wartość członka wyliczenia, która stanowi część kontraktu danych, można dostosować, wykorzystując właściwość Value atrybutu EnumMemberAttribute.
Na przykład, poniższy kontrakt danych jest równoważny kontraktowi danych z 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
Po serializacji wartość PreviouslyOwned
ma reprezentację XML <condition>Used</condition>
.
Proste wyliczenia
Można również serializować typy wyliczenia, do których DataContractAttribute atrybut nie został zastosowany. Takie typy wyliczenia są traktowane dokładnie tak, jak opisano wcześniej, z tą różnicą, że każdy element członkowski (który nie ma zastosowanego atrybutu NonSerializedAttribute ) jest traktowany tak, jakby EnumMemberAttribute atrybut został zastosowany. Na przykład poniższe wyliczenie niejawnie ma umowę danych odpowiadającą poprzedniemu przykładowi CarConditionEnum
.
public enum CarCondition
{
New,
Used,
Rental,
[NonSerialized]
Lost
}
Public Enum CarCondition
[New]
Used
Rental
End Enum
Można użyć prostych wyliczeń, gdy nie trzeba dostosowywać nazwy kontraktu danych, przestrzeni nazw oraz wartości członków wyliczenia.
Uwagi dotyczące prostych wyliczeń
Zastosowanie atrybutu EnumMemberAttribute do prostych wyliczeń nie ma efektu.
Nie ma znaczenia, czy SerializableAttribute atrybut jest stosowany do wyliczenia.
To, że klasa DataContractSerializer honoruje atrybut NonSerializedAttribute zastosowany do składowych wyliczenia, różni się od zachowania BinaryFormatter i SoapFormatter. Oba te serializatory ignorują NonSerializedAttribute atrybut .
Wyliczenia flag
Można zastosować atrybut FlagsAttribute do wyliczeń. W takim przypadku można jednocześnie wysłać lub odebrać listę zawierającą od zera do wielu wartości wyliczenia.
W tym celu zastosuj atrybut DataContractAttribute do enumeracji flagi, a następnie oznacz wszystkich członków, którzy są potęgami dwójki, atrybutem EnumMemberAttribute. Należy pamiętać, że aby użyć wyliczenia typu flaga, progresja musi być nieprzerwaną sekwencją potęg liczby 2 (na przykład 1, 2, 4, 8, 16, 32, 64).
Następujące kroki dotyczą wysyłania wartości wyliczenia flagi:
Próba znalezienia elementu wyliczenia (z zastosowanym atrybutem EnumMemberAttribute), który odpowiada wartości liczbowej. Jeśli zostanie znaleziony, wyślij listę zawierającą tylko ten element.
Spróbuj podzielić wartość liczbową na sumę, tak aby istnieli członkowie wyliczenia z przypisanym atrybutem EnumMemberAttribute, którzy odpowiadają każdej części sumy. Wyślij listę wszystkich tych członków. Należy pamiętać, że algorytm chciwości jest używany do znalezienia takiej sumy, a tym samym nie ma gwarancji, że taka suma zostanie znaleziona nawet wtedy, gdy jest obecna. Aby uniknąć tego problemu, upewnij się, że wartości liczbowe elementów członkowskich wyliczenia są potęgami liczby dwa.
Jeśli poprzednie dwa kroki kończą się niepowodzeniem, a wartość liczbowa jest niezerowa, należy zgłosić SerializationException. Jeśli wartość liczbowa to zero, wyślij pustą listę.
Przykład
Poniższy przykład wyliczenia może być używany w operacji na flagach.
[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
Poniższe przykładowe wartości są serializowane zgodnie ze wskazaniem.
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.