Compartilhar via


Tipos de enumeração em contratos de dados

As enumerações podem ser expressas no modelo de contrato de dados. Este tópico apresenta vários exemplos que explicam o modelo de programação.

Noções básicas de enumeração

Uma maneira de usar tipos de enumeração no modelo de contrato de dados é aplicar o DataContractAttribute atributo ao tipo. Em seguida, você deve aplicar o EnumMemberAttribute atributo a cada membro que deve ser incluído no contrato de dados.

O exemplo a seguir mostra duas classes. O primeiro usa a enumeração e o segundo define a enumeração.

[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

Uma instância da Car classe só poderá ser enviada ou recebida se o condition campo estiver definido como um dos valores New, Usedou Rental. Se o condition é Broken ou Stolen, um SerializationException é lançado.

Você pode usar as DataContractAttribute propriedades (Name e Namespace) como de costume para contratos de dados de enumeração.

Valores de membro de enumeração

Geralmente, o contrato de dados inclui nomes de membro de enumeração, não valores numéricos. No entanto, ao usar o modelo de contrato de dados, se o lado receptor for um cliente WCF, o esquema exportado preservará os valores numéricos. Observe que esse não é o caso ao usar a classe Using the XmlSerializer.

No exemplo anterior, se condition estiver definido Used e os dados forem serializados como XML, o XML resultante será <condition>Used</condition> e não <condition>1</condition>. Portanto, o contrato de dados a seguir é equivalente ao contrato de dados de 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

Por exemplo, você pode usar CarConditionEnum no lado de envio e CarConditionWithNumbers no lado receptor. Embora o lado de envio use o valor Used "1" e o lado receptor use o valor "20", a representação XML é <condition>Used</condition> para ambos os lados.

Para ser incluído no contrato de dados, você deve aplicar o EnumMemberAttribute atributo. No .NET Framework, você sempre pode aplicar o valor especial 0 (zero) a uma enumeração, que também é o valor padrão para qualquer enumeração. No entanto, mesmo esse valor zero especial não pode ser serializado, a menos que seja marcado com o EnumMemberAttribute atributo.

Há duas exceções para isso:

  • Enumerações de bandeiras (discutidas posteriormente neste tópico).

  • Membros de enumeração com a propriedade EmitDefaultValue definida como false (caso em que a enumeração com o valor zero é omitida dos dados serializados).

Personalizando valores de membro de enumeração

Você pode personalizar o valor do membro de enumeração que faz parte do contrato de dados usando a Value propriedade do EnumMemberAttribute atributo.

Por exemplo, o contrato de dados a seguir também é equivalente ao contrato de dados do 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

Quando serializado, o valor de PreviouslyOwned tem a representação <condition>Used</condition>XML.

Enumerações simples

Você também pode serializar tipos de enumeração aos quais o DataContractAttribute atributo não foi aplicado. Esses tipos de enumeração são tratados exatamente como descrito anteriormente, exceto que cada membro (que não tem o NonSerializedAttribute atributo aplicado) é tratado como se o EnumMemberAttribute atributo tivesse sido aplicado. Por exemplo, a enumeração a seguir tem implicitamente um contrato de dados equivalente ao exemplo anterior CarConditionEnum .

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

Você pode usar enumerações simples quando não precisar personalizar o nome e o namespace do contrato de dados da enumeração e os valores dos membros da enumeração.

Anotações sobre enumerações simples

A aplicação do EnumMemberAttribute atributo a enumerações simples não tem efeito.

Não faz diferença se o SerializableAttribute atributo é aplicado ou não à enumeração.

O fato de a DataContractSerializer classe honrar o NonSerializedAttribute atributo aplicado aos membros de enumeração é diferente do comportamento do BinaryFormatter e do SoapFormatter. Esses dois serializadores ignoram o NonSerializedAttribute atributo.

Enumerações de sinalizador

Você pode aplicar o FlagsAttribute atributo a enumerações. Nesse caso, uma lista de zero ou mais valores de enumeração pode ser enviada ou recebida simultaneamente.

Para fazer isso, aplique o atributo DataContractAttribute à enumeração de sinalizadores e marque todos os membros que são potências de dois com o atributo EnumMemberAttribute. Observe que, para usar uma enumeração de sinalizador, a progressão deve ser uma sequência ininterrupta de poderes de 2 (por exemplo, 1, 2, 4, 8, 16, 32, 64).

As etapas a seguir se aplicam ao envio do valor de enumeração de um sinalizador:

  1. Tente encontrar um membro de enumeração que corresponda ao valor numérico, com o atributo EnumMemberAttribute aplicado. Se encontrado, envie uma lista que contenha apenas esse membro.

  2. Tente dividir o número em uma soma de forma que existam membros de enumeração (cada um com o atributo EnumMemberAttribute aplicado) que correspondam a cada parte da soma. Envie a lista de todos esses membros. Observe que o algoritmo greedy é usado para encontrar tal soma e, portanto, não há nenhuma garantia de que tal soma seja encontrada mesmo se ela estiver presente. Para evitar esse problema, verifique se os valores numéricos dos membros de enumeração são poderes de dois.

  3. Se as duas etapas anteriores falharem e o valor numérico não for zero, gere um SerializationException. Se o valor numérico for zero, envie a lista vazia.

Exemplo

O exemplo de enumeração a seguir pode ser usado em uma operação de sinalizador.

[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

Os valores de exemplo a seguir são serializados conforme indicado.

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.

Consulte também