Condividi tramite


Tipi di enumerazioni nei contratti dati

Le enumerazioni possono essere espresse nel modello del contratto dati. In questo argomento vengono esaminati molti esempi che spiegano il modello di programmazione.

Nozioni fondamentali sull'enumerazione

Per usare i tipi di enumerazione nel modello del contratto dati, applicare l'attributo DataContractAttribute al tipo. Applicare quindi l'attributo EnumMemberAttribute a ogni membro che deve essere incluso nel contratto dati.

Nell'esempio che segue vengono illustrate due classi. La prima usa l'enumerazione e la seconda definisce l'enumerazione.

[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

Un'istanza della classe Car può essere inviata o ricevuta solo se il campo condition è impostato su uno dei valori New, Used o Rental. Se condition è Broken o Stolen, viene generata un'eccezione SerializationException.

È possibile usare come al solito le proprietà DataContractAttribute (Name e Namespace) per i contratti dati dell'enumerazione.

Valori membro dell'enumerazione

In genere il contratto dati include i nomi dei membri dell'enumerazione, non i valori numerici. Tuttavia, quando si usa il modello del contratto dati, se il lato ricevente è un client WCF, lo schema esportato mantiene i valori numerici. Si noti che questo non accade quando si usa Utilizzo di XmlSerializer Class.

Nell'esempio precedente, se condition è impostato su Used e i dati vengono serializzati in XML, il codice XML risultante è <condition>Used</condition><condition>1</condition> e non . Di conseguenza, il contratto dati seguente è equivalente al contratto dati di 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

Ad esempio, è possibile usare CarConditionEnum sul lato mittente e CarConditionWithNumbers sul lato ricevente. Sebbene il lato mittente usi il valore "1" per Used e il lato ricevente usi il valore "20", la rappresentazione XML è <condition>Used</condition> per entrambi i lati.

Per essere incluso nel contratto dati, è necessario applicare l'attributo EnumMemberAttribute. In .NET Framework, è sempre possibile applicare il valore speciale 0 (zero) a un'enumerazione che è anche il valore predefinito per qualsiasi enumerazione. Tuttavia, anche il valore speciale zero non può essere serializzato a meno che sia contrassegnato con l'attributo EnumMemberAttribute.

Esistono due eccezioni a questo contesto:

  • Enumerazioni di flag (esaminate più avanti in questo argomento).

  • Membri dati dell'enumerazione con la proprietà EmitDefaultValue impostata su false (in tal caso l'enumerazione con valore zero viene omessa dai dati serializzati).

Personalizzazione dei valori membro dell'enumerazione

È possibile personalizzare il valore del membro dell'enumerazione che costituisce una parte del contratto dati usando la proprietà Value dell'attributo EnumMemberAttribute.

Ad esempio, il contratto dati seguente è equivalente anche al contratto dati di 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

Una volta serializzato, il valore di PreviouslyOwned contiene la rappresentazione XML <condition>Used</condition>.

Enumerazioni semplici

È anche possibile serializzare i tipi di enumerazione ai quali non è stato applicato l'attributo DataContractAttribute. Tali tipi di enumerazione vengono trattati esattamente come descritto in precedenza, con l'eccezione che ogni membro, a cui non è applicato l'attributo NonSerializedAttribute, viene trattato come se fosse stato applicato l'attributo EnumMemberAttribute. Ad esempio, l'enumerazione seguente contiene implicitamente un contratto dati equivalente all'esempio CarConditionEnum precedente.

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

È possibile usare le enumerazioni semplici quando non è necessario personalizzare lo spazio dei nomi e il nome del contratto dati dell'enumerazione e i valori membro dell'enumerazione.

Nota sulle enumerazioni semplici

L'applicazione dell'attributo EnumMemberAttribute alle enumerazioni semplici non produce alcun effetto.

È indifferente se l'attributo SerializableAttribute viene applicato o meno all'enumerazione.

Il fatto che la classe DataContractSerializer si basa sull'applicazione dell'attributo NonSerializedAttribute ai membri dell'enumerazione è diverso dal comportamento di BinaryFormatter e SoapFormatter. Entrambi i serializzatori ignorano l'attributo NonSerializedAttribute.

Enumerazioni di flag

È possibile applicare l'attributo FlagsAttribute alle enumerazioni. In tal caso, è possibile inviare o ricevere simultaneamente un elenco di zero o più valori di enumerazione.

A tale scopo, applicare l'attributo DataContractAttribute all'enumerazione del flag e quindi contrassegnare tutti i membri che sono potenze di due con l'attributo EnumMemberAttribute. Si noti che per usare un'enumerazione del flag, la progressione deve essere una sequenza ininterrotta di potenze di 2 (ad esempio, 1, 2, 4, 8, 16, 32, 64).

I passaggi seguenti si applicano all'invio del valore dell'enumerazione di un flag:

  1. Tentare di individuare un membro dell'enumerazione (a cui è applicato l'attributo EnumMemberAttribute) associato al valore numerico. Se disponibile, inviare un elenco che contenga solo quel membro.

  2. Tentare di suddividere il valore numerico in una somma tale che vi siano membri dell'enumerazione (ai quali è applicato l'attributo EnumMemberAttribute) associati a ogni parte della somma. Inviare l'elenco di tutti questi membri. Poiché viene usato l'algoritmo di tipo greedy per trovare tale somma, non è possibile garantire che tale somma venga trovata anche se è presente. Per evitare questo problema, verificare che i valori numerici dei membri dell'enumerazione siano potenze di due.

  3. Se i due passaggi precedenti hanno esito negativo e il valore numerico è diverso da zero, generare un'eccezione SerializationException. Se il valore numerico è zero, inviare l'elenco vuoto.

Esempio

L'esempio di enumerazione seguente può essere usato in un'operazione di flag.

[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

I valori nell'esempio seguente vengono serializzati come indicato.

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.

Vedi anche