Uppräkningstyper i datakontrakt
Uppräkningar kan uttryckas i datakontraktsmodellen. Det här avsnittet går igenom flera exempel som förklarar programmeringsmodellen.
Grundläggande om uppräkning
Ett sätt att använda uppräkningstyper i datakontraktsmodellen är att tillämpa DataContractAttribute attributet på typen. Du måste sedan använda EnumMemberAttribute attributet för varje medlem som måste ingå i datakontraktet.
I följande exempel visas två klasser. Den första använder uppräkningen och den andra definierar uppräkningen.
[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
En instans av Car
klassen kan endast skickas eller tas emot om fältet condition
är inställt på något av värdena New
, Used
eller Rental
. condition
Om är Broken
eller Stolen
genereras enSerializationException.
Du kan använda DataContractAttribute egenskaperna (Name och Namespace) som vanligt för uppräkningsdatakontrakt.
Uppräkningsmedlemsvärden
I allmänhet innehåller datakontraktet uppräkningsmedlemsnamn, inte numeriska värden. Men när du använder datakontraktsmodellen bevarar det exporterade schemat de numeriska värdena om den mottagande sidan är en WCF-klient. Observera att detta inte är fallet när du använder klassen Using the XmlSerializer .
I föregående exempel, om condition
är inställt på Used
och data serialiseras till XML, är <condition>Used</condition>
den resulterande XML:en och inte <condition>1</condition>
. Därför motsvarar följande datakontrakt datakontraktet CarConditionEnum
för .
[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
Du kan till exempel använda CarConditionEnum
på sändningssidan och CarConditionWithNumbers
på mottagarsidan. Även om den sändande sidan använder värdet "1" för Used
och den mottagande sidan använder värdet "20", är <condition>Used</condition>
XML-representationen för båda sidor.
Om du vill inkluderas i datakontraktet måste du använda attributet EnumMemberAttribute . I .NET Framework kan du alltid använda specialvärdet 0 (noll) för en uppräkning, vilket också är standardvärdet för alla uppräkningar. Men inte ens det här speciella nollvärdet kan serialiseras om det inte är markerat med attributet EnumMemberAttribute .
Det finns två undantag till detta:
Flagga uppräkningar (beskrivs senare i det här avsnittet).
Uppräkningsdatamedlemmar med EmitDefaultValue egenskapen inställd på
false
(i så fall utelämnas uppräkningen med värdet noll från serialiserade data).
Anpassa uppräkningsmedlemsvärden
Du kan anpassa uppräkningsmedlemsvärdet som utgör en del av datakontraktet med hjälp Value av egenskapen för EnumMemberAttribute attributet.
Till exempel motsvarar följande datakontrakt även datakontraktet för 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
När det serialiseras har värdet PreviouslyOwned
för XML-representationen <condition>Used</condition>
.
Enkla uppräkningar
Du kan också serialisera uppräkningstyper som DataContractAttribute attributet inte har tillämpats på. Sådana uppräkningstyper behandlas exakt som tidigare beskrivits, förutom att varje medlem (som inte har NonSerializedAttribute attributet tillämpat) behandlas som om EnumMemberAttribute attributet har tillämpats. Följande uppräkning har till exempel implicit ett datakontrakt som motsvarar föregående CarConditionEnum
exempel.
public enum CarCondition
{
New,
Used,
Rental,
[NonSerialized]
Lost
}
Public Enum CarCondition
[New]
Used
Rental
End Enum
Du kan använda enkla uppräkningar när du inte behöver anpassa uppräkningsnamnet och namnområdet för datakontraktet och uppräkningsmedlemsvärdena.
Anteckningar om enkla uppräkningar
Att tillämpa attributet på EnumMemberAttribute enkla uppräkningar har ingen effekt.
Det spelar ingen roll om attributet tillämpas på uppräkningen eller inte SerializableAttribute .
Det faktum att DataContractSerializer klassen respekterar attributet NonSerializedAttribute som tillämpas på uppräkningsmedlemmar skiljer sig från beteendet för BinaryFormatter och SoapFormatter. Båda dessa serialiserare ignorerar attributet NonSerializedAttribute .
Flagga uppräkningar
Du kan använda attributet FlagsAttribute för uppräkningar. I så fall kan en lista med noll eller fler uppräkningsvärden skickas eller tas emot samtidigt.
Om du vill göra det använder du DataContractAttribute attributet för flagguppräkningen och markerar sedan alla medlemmar som har två behörigheter med EnumMemberAttribute attributet . Observera att om du vill använda en flagguppräkning måste förloppet vara en oavbruten sekvens av krafter på 2 (till exempel 1, 2, 4, 8, 16, 32, 64).
Följande steg gäller för att skicka en flaggas uppräkningsvärde:
Försök att hitta en uppräkningsmedlem (med attributet EnumMemberAttribute tillämpat) som mappar till det numeriska värdet. Om det hittas skickar du en lista som bara innehåller den medlemmen.
Försök att dela upp det numeriska värdet i en summa så att det finns uppräkningsmedlemmar (var och en med attributet EnumMemberAttribute tillämpat) som mappas till varje del av summan. Skicka listan över alla dessa medlemmar. Observera att den giriga algoritmen används för att hitta en sådan summa, och därför finns det ingen garanti för att en sådan summa hittas även om den finns. För att undvika det här problemet kontrollerar du att de numeriska värdena för uppräkningsmedlemmarna är två.
Om de föregående två stegen misslyckas och det numeriska värdet inte ärzero genererar du en SerializationException. Om det numeriska värdet är noll skickar du den tomma listan.
Exempel
Följande uppräkningsexempel kan användas i en flaggåtgärd.
[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
Följande exempelvärden serialiseras enligt angivet.
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.