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
, Used
ou 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:
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.
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.
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.