2009-08-27 8 views
14

Chaque fois que j'utilise WCF, j'essaie toujours de rendre les classes immuables qui finissent par passer par le réseau (c'est-à-dire les paramètres définis dans le constructeur, les propriétés sont en lecture seule). Cependant, cela entrave la sérialisation WCF, qui exige que toutes les propriétés soient publiques get/set (ce qui est logique, car il faut les désérialiser)WCF DataContract sérialisation des propriétés en lecture seule?

Même dans this related post, je vois que leur solution a fini par tout faire Public, ce qui viole mon sens de la bonne programmation. Y at-il un moyen de contourner cela? Est-ce que je dois me contenter de cette solution ou de quelque chose comme l'immuabilité de la popsicle et être heureux avec elle?

L'autre chose que j'ai essayé était quelque chose comme ça, où j'aurais une classe de base pour tout et une classe dérivée qui a fait le jeu inutile:

/// <summary> 
/// This represents a discovered virtual-machine template that can be 
/// instantiated into a RunningVirtualMachine 
/// </summary> 
[DataContract] 
[XmlRoot("VMTemplate")] 
public class VirtualMachineTemplateBase 
{ 
    [DataMember] 
    public virtual ulong SizeInBytes { get; set; } 
} 

/// <summary> 
/// This class is the real guts of VirtualMachineTemplate that we're hiding 
/// from the base class. 
/// </summary> 
[XmlInclude(typeof(VirtualMachineTemplateBase))] 
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger 
{ 
    ulong _SizeInBytes; 
    public override ulong SizeInBytes { 
     get { return _SizeInBytes; } 
     set { } 
    } 
} 

Répondre

15

Si vous utilisez le DataContractSerializer (ce qui est le par défaut pour WCF), vous pouvez sérialiser anyhting qui est décorée avec l'attribut [DataMember] - même un champ de lecture seule:

[DataContract] 
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger 
{ 
    [DataMember] 
    ulong _SizeInBytes; 
} 

Mais vous devez utiliser DataContractSerializer - pas le sérialiseur XML. Le sérialiseur XML peut UNIQUEMENT sérialiser les propriétés publiques (et il le fera, à moins que vous ne mettiez un [XmlIgnore] dessus).

DataContractSerializer est différent:

  • il n'a pas besoin d'un paramètre moins constructeur par défaut
  • il sera seulement serialize ce que vous marquez explicitement [DataMember]
  • mais qui peut être quelque chose - un champ, une propriété et de toute visibilité (privé, protégé, public)
  • c'est un peu plus rapide que XmlSerializer, mais vous n'avez pas beaucoup de contrôle sur la forme du XML - vous obtenez seulement un mot à dire dans ce qui est inclus

Voir cette blog post et ce blog post pour quelques trucs et astuces.

Marc

+12

Non, vous devez toujours inclure l'ensemble ou il échoue. – Craig

+0

Vous pouvez définir SerializeReadOnlyTypes sur true dans DataContractSerializerSettings. –

+0

Aw, les liens blog sont morts maintenant :( –

3

Pour assurer à la fois l'immuabilité et la mise en œuvre facile en même temps ajouter un setter privé pour la propriété de servir désérialisation. Il se passe beaucoup de choses sous le capot, mais ça marche.