Compartir a través de


Tipos de enumeración en contratos de datos

Las enumeraciones se pueden expresar en el modelo del contrato de datos. En este tema se exponen varios ejemplos que explican el modelo de programación.

Fundamentos de enumeración

Una manera de utilizar tipos de enumeración en el modelo del contrato de datos es aplicar el atributo DataContractAttribute al tipo. Debe aplicar a continuación el atributo EnumMemberAttribute a cada miembro que debe estar incluido en el contrato de datos.

En el ejemplo siguiente se muestran dos clases. El primero utiliza la enumeración y el segundo define la enumeración.

[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

Una instancia de la clase Car se puede enviar o recibir solo si el campo condition está establecido en uno de los valores New, Usedo Rental. Si la propiedad condition es Broken o Stolen, se produce SerializationException.

Puede utilizar las propiedades (DataContractAttribute y Name) Namespace de forma habitual para los contratos de datos de enumeración.

Valores miembro de enumeración

Generalmente, el contrato de datos incluye nombres miembro de enumeración, no valores numéricos. Sin embargo, al utilizar el modelo del contrato de datos, si el lado receptor es un cliente WCF, el esquema exportado conserva los valores numéricos. Tenga en cuenta que este no es el caso en la Utilización de la clase XmlSerializer.

En el ejemplo anterior, si condition está establecido en Used y se serializan los datos a XML, el XML resultante es <condition>Used</condition><condition>1</condition> y no . Por consiguiente, el contrato de datos siguiente es equivalente al contrato de datos 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 ejemplo, puede utilizar CarConditionEnum en el lado emisor y CarConditionWithNumbers en el lado receptor. Aunque el lado emisor usa el valor "1" para Used y el lado receptor usa el valor "20", la representación XML es <condition>Used</condition> para ambos lados.

Para que se incluya en el contrato de datos, debe aplicar el atributo EnumMemberAttribute. En .NET Framework, siempre puede aplicar el valor especial 0 (cero) a una enumeración, que también es el valor predeterminado para cualquier enumeración. Sin embargo, este valor especial cero no se puede serializar a menos que se marque con el atributo EnumMemberAttribute.

Existen dos excepciones a esto:

  • Enumeraciones de marcas (se describe más adelante en este tema).

  • Miembros de datos de enumeración con la propiedad EmitDefaultValue establecida en false (en cuyo caso la enumeración con el valor cero se omite de los datos serializados).

Personalización de valores miembro de enumeración

Puede personalizar el valor miembro de enumeración que constituye una parte del contrato de datos utilizando la propiedad Value del atributo EnumMemberAttribute.

Por ejemplo, el siguiente contrato de datos es también equivalente al contrato de datos de 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

Cuando se serializa, el valor de PreviouslyOwned tiene representación XML <condition>Used</condition>.

Enumeraciones simples

También puede serializar los tipos de enumeración a los que no se ha aplicado el atributo DataContractAttribute. Estos tipos de enumeración se tratan tal y como se ha descrito anteriormente, a excepción de que cada miembro (que no tiene el atributo NonSerializedAttribute aplicado) se trata como si se hubiera aplicado el atributo EnumMemberAttribute. Por ejemplo, la enumeración siguiente tiene de forma implícita un contrato de datos equivalente al del ejemplo de CarConditionEnum anterior.

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

Puede usar las enumeraciones simples cuando no necesite personalizar el espacio de nombres y el nombre del contrato de datos de la enumeración y los valores miembro de la enumeración.

Notas en enumeraciones simples

Aplicar el atributo EnumMemberAttribute a las enumeraciones simples no tiene ningún efecto.

No se produce ninguna diferencia si se aplica el atributo SerializableAttribute o no a la enumeración.

El hecho que la clase DataContractSerializer acepte el atributo NonSerializedAttribute aplicado a los miembros de enumeración es diferente del comportamiento de BinaryFormatter y SoapFormatter. Ambos de esos serializadores omiten el atributo NonSerializedAttribute.

Enumeraciones de marcas

Puede aplicar el atributo FlagsAttribute a enumeraciones. En ese caso, una lista de cero o más valores de enumeración se puede enviar o recibir simultáneamente.

Para ello, aplique el atributo DataContractAttribute a la enumeración de marca y, a continuación, marque todos los miembros que son potencias de dos con el atributo EnumMemberAttribute. Tenga en cuenta que para utilizar una enumeración de marca, la progresión debe ser una secuencia ininterrumpida de potencias de 2 (por ejemplo, 1, 2, 4, 8, 16, 32, 64).

Los pasos siguientes se aplican al envío de un valor de enumeración de un marca:

  1. Intente buscar un miembro de enumeración (con el atributo EnumMemberAttribute aplicado) que asigna al valor numérico. Si lo encuentra, envíe una lista que contenga solo ese miembro.

  2. Intente desglosar el valor numérico en una suma de tal forma que haya miembros de enumeración (cada uno con el atributo EnumMemberAttribute aplicado) que estén asignados a cada parte de la suma. Envíe la lista de todos estos miembros. Tenga en cuenta que se usa el algoritmo expansivo para buscar la suma, y, por lo tanto, no hay ninguna garantía de que se vaya a encontrar, aunque exista. Para evitar este problema, asegúrese de que los valores numéricos de los miembros de enumeración son potencias de dos.

  3. Si los dos pasos anteriores fallan, y el valor numérico es distinto de cero, inicie SerializationException. Si el valor numérico es cero, envíe la lista vacía.

Ejemplo

El ejemplo de enumeración siguiente se puede utilizar en una operación de la marca.

[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

Los valores de ejemplo siguientes se serializan tal y como se ha 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.

Vea también