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 utilizzare 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 utilizza l'enumerazione e la seconda definisce l'enumerazione.
<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
[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
}
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 utilizzare 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 utilizza il modello del contratto dati, se il lato ricevente è un client WCF, lo schema esportato mantiene i valori numerici. La situazione è diversa quando si utilizza Utilizzo della classe XmlSerializer.
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> NewCar = 10
<EnumMember> Used = 20
<EnumMember> Rental = 30
End Enum
[DataContract(Name = "CarCondition")]
public enum CarConditionWithNumbers
{
[EnumMember]
New = 10,
[EnumMember]
Used = 20,
[EnumMember]
Rental = 30,
}
Ad esempio, è possibile utilizzare CarConditionEnum
sul lato mittente e CarConditionWithNumbers
sul lato ricevente. Sebbene il lato mittente utilizza il valore "1" per Used
e il lato ricevente utilizza 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 utilizzando 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
End Enum
[DataContract(Name = "CarCondition")]
public enum CarConditionWithDifferentNames
{
[EnumMember(Value = "New")]
BrandNew,
[EnumMember(Value = "Used")]
PreviouslyOwned,
[EnumMember]
Rental
}
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
End Enum
public enum CarCondition
{
New,
Used,
Rental,
[NonSerialized]
Lost
}
È possibile utilizzare 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 utilizzare 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:
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.
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 utilizzato 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.
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 utilizzato 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 Or AutomaticTransmission Or PowerDoors Or AlloyWheels
<EnumMember> CDPlayer = 16
<EnumMember> TapePlayer = 32
MusicPackage = CDPlayer Or TapePlayer
<EnumMember>Everything = DeluxePackage Or MusicPackage
End Enum
[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
}
I valori nell'esempio seguente vengono serializzati come indicato.
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.
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
Vedere anche
Riferimento
Concetti
Utilizzo di contratti dati
Specifica del trasferimento di dati nei contratti di servizio