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 pode ser enviada ou recebida somente 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 membros de enumeração, não valores numéricos. No entanto, ao usar o modelo de contrato de dados, se o lado recetor for um cliente WCF, o esquema exportado preserva os valores numéricos. Observe que esse não é o caso ao usar a classe XmlSerializer.

No exemplo anterior, se condition estiver definido como Used e os dados forem serializados para XML, o XML resultante será <condition>Used</condition> e não <condition>1</condition>. Portanto, o seguinte contrato de dados é 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 de recebimento. Embora o lado de envio use o valor "1" para Used e o lado recetor 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.

Existem duas exceções:

  • Enumerações de sinalizadores (discutidas mais adiante neste tópico).

  • Membros de dados de enumeração com a EmitDefaultValue propriedade definida como false (nesse caso, 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 seguinte contrato de dados 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. Tais 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 implicitamente tem 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 precisa personalizar o nome e o namespace do contrato de dados da enumeração e os valores de membro da enumeração.

Notas 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 é ou não aplicado à enumeração.

O fato de que a DataContractSerializer classe honra o NonSerializedAttribute atributo aplicado aos membros da enumeração é diferente do comportamento do BinaryFormatter e do SoapFormatter. Ambos os serializadores ignoram o NonSerializedAttribute atributo.

Enumerações de Sinalizadores

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 DataContractAttribute atributo à enumeração de sinalizador e, em seguida, marque todos os membros que são poderes de dois com o EnumMemberAttribute atributo. 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 localizar um membro de enumeração (com o EnumMemberAttribute atributo aplicado) que mapeie para o valor numérico. Se encontrado, envie uma lista que contenha apenas esse membro.

  2. Tente dividir o valor numérico em uma soma tal que haja membros de enumeração (cada um com o EnumMemberAttribute atributo aplicado) que mapeiam para cada parte da soma. Envie a lista de todos esses membros. Note que o algoritmo ganancioso é usado para encontrar tal soma e, portanto, não há garantia de que tal soma seja encontrada, mesmo que esteja presente. Para evitar esse problema, certifique-se de que os valores numéricos dos membros da enumeração são poderes de dois.

  3. Se as duas etapas anteriores falharem e o valor numérico for diferente de zero, lance um SerializationExceptionarquivo . 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