Share via


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, Usednebo 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:

  1. 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.

  2. 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.

  3. 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.

Viz také