Výčtové typy v kontraktech dat
Výčty lze vyjádřit v modelu kontraktu dat. Toto téma vás provede několika příklady, které vysvětlují programovací model.
Základy výčtu
Jedním ze způsobů, jak použít typy výčtu v modelu kontraktu dat, je použít DataContractAttribute atribut na typ. Pak musíte atribut použít EnumMemberAttribute pro každého člena, který musí být zahrnut do datové smlouvy.
Následující příklad ukazuje dvě třídy. První používá výčet a druhý definuje výčet.
[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
Instanci Car
třídy lze odeslat nebo přijímat pouze v případě, že condition
je pole nastaveno na jednu z hodnot New
, Used
nebo Rental
. condition
Pokud je Broken
nebo Stolen
, SerializationException je vyvolán.
Vlastnosti (NameaNamespace) můžete použít DataContractAttribute jako obvykle pro výčtové kontrakty dat.
Hodnoty členů výčtu
Obecně platí, že kontrakt dat obsahuje názvy členů výčtu, nikoli číselné hodnoty. Pokud je však přijímající strana klientem WCF, při použití modelu kontraktu dat zachová exportované schéma číselné hodnoty. Všimněte si, že to není případ při použití Třídy Using XmlSerializer.
V předchozím příkladu, pokud condition
je nastavena Used
na a data jsou serializována do XML, výsledný XML je <condition>Used</condition>
a nikoli <condition>1</condition>
. Z tohoto důvodu je následující datový kontrakt ekvivalentní datové smlouvě .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
Můžete například použít CarConditionEnum
na straně odesílání a CarConditionWithNumbers
na straně příjmu. I když odesílající strana používá hodnotu "1" pro Used
a přijímající strana používá hodnotu "20", reprezentace XML je <condition>Used</condition>
pro obě strany.
Pokud chcete být zahrnuti do datového kontraktu EnumMemberAttribute , musíte použít atribut. V rozhraní .NET Framework můžete vždy použít speciální hodnotu 0 (nula) na výčet, což je také výchozí hodnota pro všechny výčty. I tuto speciální nulovou hodnotu však nelze serializovat, pokud není označen atributem EnumMemberAttribute .
Existují dvě výjimky:
Výčty příznaků (popsané dále v tomto tématu).
Datové členy výčtu s vlastností nastavenou EmitDefaultValue na
false
(v takovém případě je výčet s hodnotou nula vynechán ze serializovaných dat).
Přizpůsobení hodnot členů výčtu
Hodnotu člena výčtu, která tvoří součást datového kontraktu, můžete přizpůsobit pomocí Value vlastnosti atributu EnumMemberAttribute .
Například následující datový kontrakt je také ekvivalentní datovému kontraktu 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
Při serializaci má hodnota PreviouslyOwned
reprezentace <condition>Used</condition>
XML .
Jednoduché výčty
Můžete také serializovat typy výčtu, na které DataContractAttribute atribut nebyl použit. Takové typy výčtu jsou považovány za přesně tak, jak jsme popsali dříve, s tím rozdílem, že každý člen (který nemá NonSerializedAttribute použitý atribut) je považován za předpokladu EnumMemberAttribute , že byl atribut použit. Například následující výčet implicitně obsahuje kontrakt dat ekvivalentní předchozímu CarConditionEnum
příkladu.
public enum CarCondition
{
New,
Used,
Rental,
[NonSerialized]
Lost
}
Public Enum CarCondition
[New]
Used
Rental
End Enum
Jednoduché výčty můžete použít v případě, že nepotřebujete přizpůsobit název a obor názvů datového kontraktu výčtu a hodnoty členů výčtu.
Poznámky k jednoduchým výčtům
Použití atributu EnumMemberAttribute na jednoduché výčty nemá žádný vliv.
Nezáleží na tom, zda SerializableAttribute je atribut použit na výčet.
Skutečnost, že DataContractSerializer třída respektuje NonSerializedAttribute atribut použitý na výčtové členy se liší od chování BinaryFormatter a SoapFormatter. Oba tyto serializátory atribut ignorují NonSerializedAttribute .
Výčty příznaků
Atribut můžete použít FlagsAttribute na výčty. V takovém případě může být současně odeslán nebo přijat seznam nulových nebo více hodnot výčtu.
Uděláte to tak, že na výčet příznaku použijete DataContractAttribute atribut a označíte všechny členy, které jsou mocné dvěma s atributem EnumMemberAttribute . Všimněte si, že pokud chcete použít výčet příznaků, musí být průběh nepřerušenou posloupností mocnin 2 (například 1, 2, 4, 8, 16, 32, 64).
Následující kroky platí pro odeslání hodnoty výčtu příznaku:
Pokus o vyhledání členu výčtu (s použitým EnumMemberAttribute atributem), který se mapuje na číselnou hodnotu. Pokud se najde, odešlete seznam, který obsahuje jenom daného člena.
Pokus o rozdělení číselné hodnoty na součet tak, aby byly k dispozici členy výčtu (každý s použitým EnumMemberAttribute atributem), které se mapují na každou část součtu. Odešlete seznam všech těchto členů. Všimněte si, že algoritmus greedy se používá k nalezení takového součtu, a proto neexistuje žádná záruka, že takový součet se najde i v případě, že existuje. Chcete-li se tomuto problému vyhnout, ujistěte se, že číselné hodnoty členů výčtu jsou mocniny dvou.
Pokud předchozí dva kroky selžou a číselná hodnota je nenulová, vyvoláte výjimku SerializationException. Pokud je číselná hodnota nula, odešlete prázdný seznam.
Příklad
Následující příklad výčtu lze použít v operaci příznaku.
[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
Následující ukázkové hodnoty jsou serializovány, jak je uvedeno.
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.