2009-02-17 5 views
53
membre

Dans WCF, quelle est la différence entre l'application de l'attribut DataMember sur une propriétéWCF: DataMember attribut sur la propriété par rapport à

private int m_SomeValue; 

[DataMember] 
public int SomeValue { 
    get {...} 
    set {...} 
} 

au lieu d'une variable membre

[DataMember] 
private int m_SomeValue; 

public int SomeValue { 
    get {...} 
    set {...} 
} 

?

+1

vous n'avez pas besoin de faire d'une variable privée un membre de données. –

Répondre

41

En général, vous devriez préférer appliquer l'attribut DataMember sur la propriété plutôt que sur le champ privé. La seule raison d'appliquer l'attribut au champ à la place est si la propriété était en lecture seule (c'est-à-dire qu'elle n'a pas de setter).

+2

Pourquoi avons-nous besoin de faire cela si? – Krishna

+2

Toutes les sérialisations dans WCF sont bidirectionnelles par défaut. Cela signifie que le framework doit être capable de lire et d'écrire tous vos éléments de données.Ainsi, si vous modifiez un type existant avec des propriétés en lecture seule à sérialiser, vous devrez peut-être ajouter les attributs à un champ. C'est un cas rare, cependant. – dthrasher

+5

Il est également utile de placer le DataMemberAttribute sur un champ si le getter/setter de votre propriété contient du code susceptible de modifier sa valeur. – rossisdead

3

En théorie, et aussi longtemps que vous gardez m_SomeValue toujours égal à SomeValue (comme un simple getter/setter), rien. Autre que le nom de la variable exposée par la WCF. (De toute évidence, si vous marquez la variable m_, votre classe de proxy aura également le même nom m_. La classe de proxy générera une propriété publique que vous utilisiez un champ ou une propriété public/protected/interne/private

Cependant Si vous avez une logique spéciale dans vos accesseurs qui peut modifier la valeur renvoyée (ToUpper() par exemple, une chaîne, par exemple), vous obtiendrez alors une valeur différente:

24

Tant que vous utilisez le marqueur Name, le contrat est identique, que le champ ou la propriété soit utilisé ou non

[DataMember(Name="SomeValue")] 
private int m_SomeValue; 

Cependant, il peut y avoir quelques problèmes d'autorisations d'accès aux membres privés, en particulier sur Silverlight et CF - dans ce cas, je recommanderais d'utiliser la propriété publique en tant que membre de données. En fait, j'aurais tendance à toujours utiliser une propriété sauf si j'avais une très bonne raison ...

+0

Je suis totalement en désaccord avec vous Marc, voir mon asnwer, je voudrais entendre votre réponse à ce sujet http://stackoverflow.com/a/8442768/235715 –

+0

@Alex répondu comme demandé –

2

Personnellement, je voudrais juste utiliser la propriété et complètement supprimé la variable membre tous ensemble. c'est-à-dire

[DataMember] 
public int SomeValue 
{ get; set; } 

La propriété va inexplicablement créer une variable membre dans les coulisses.

+7

"inexplicablement"? C'est ce que ça veut dire. Peut-être que vous vouliez dire "implicitement"? –

+3

Comment le sait-il? – Will

+0

Le compilateur C# génère un champ "backing" privé avec un nom tronqué (pour empêcher la collision avec le nom de tout autre champ que vous avez défini) pour la propriété auto. – Kit

1

Si vous ajoutez [DataMember] sur private int m_SomeValue, ce membre ne peut pas être sérialisé, il doit donc être ajouté sur public int SomeValue.

[DataMember]
private int m_SomeValue;

SomeValue public int { get {...} ensemble {...}}

le code ci-dessus ne peut être obtenir la valeur dans le client si vous l'utilisez par WCF.

+3

DataContractSerializers sérialisera tout champ privé sur lequel DataMemberAttribute est associé. – rossisdead

+0

Je suis d'accord avec rossisdead, tout champ privé a DataMemberattribute est sérialisé, et est exposé par le service au client. – Niraj

6

Il existe de bonnes raisons de marquer des champs plutôt que des propriétés comme DataMember.

S'il vous plaît vérifier pour plus de détails: http://blog.walteralmeida.com/2010/05/wcf-and-datacontract-serialization-internals-and-tips-.html

Par ailleurs: ContractSerializers va sérialiser un domaine privé qui a le DataMemberAttribute sur elle que si vous travaillez dans un environnement plein de confiance.Ne fonctionne pas en confiance partielle (consultez le blog ci-dessus pour une solution)

4

Ce decission dépend de l'utilisation de vous WCF service:

  1. Service interne consommée par vous propres systèmes .NET, qui partagent les même modèle de domaine.
  2. Service externe consommé par différentes plates-formes, qui ne partagent pas le même modèle de domaine.

Cas 1.

sérialisation - est le processus de l'état persistant de l'objet. L'état de l'objet en C# est représenté par ses champs de données.

Les propriétés de C# sont essentiellement des méthodes qui manipulent l'état de l'objet. Leur utilisation peut entraîner une désérialisation différente de l'état de l'objet, car l'ordre dans lequel les propriétés sont définies peut avoir un impact sur l'état final des données. D'autres facteurs peuvent entraîner une désérialisation incorrecte de l'état, par exemple si method (jeu de propriétés) repose sur un contexte qui change, comme DateTime actuel.

Vous pouvez dire quoi sur l'encapsulation? Je ne veux pas que mon objet soit dans un état invalide, et je dois faire des vérifications de validation, des vérifications d'intégrité de graphique d'objet, etc. Oui, vous devriez, ainsi nous mettons les attributs de DataMember sur des accessoires? Le problème ici est que beaucoup de personnes mélangent deux choses différentes, DTO (objet de transfert de données, contrat WCF) avec l'entité de domaine. Ce dont vous avez besoin, c'est de vous assurer que les données que vous recevez sont exactement les mêmes que celles qui ont été envoyées, puis assurez-vous que vous pouvez construire une entité de domaine valide à partir de ces données. La meilleure façon d'y parvenir est d'utiliser des classes séparées pour les objets DTO et de construire l'entité de domaine à partir d'eux.

Mais la plupart des programmeurs sont paresseux, et ils aiment décorer simplement l'entité de domaine avec les attributs DataMemeber. Dans ce cas, la décision Champ ou Prop dépend de votre logique de validation, si votre logique de validation est enterrée dans les méthodes Set, vous devrez utiliser Props, si elle est externe, vous devrez utiliser Fields et valider votre entité de domaine après désialisation.

P.S. Je pense que les mêmes règles s'appliquent à tout processus de sérialisation, comme la persistance de la base de données.

Aussi, je voudrais mentionner que Silverlight ne peut pas sérialiser \ désérialiser des champs privés, parce que vous ne pouvez pas y accéder de l'extérieur en utilisant la réflexion, et vous devrez les rendre privés et utiliser InternalsVisibleToAttribute.

Case 2.

Il est difficile une. L'objectif principal ici est l'interopérabilité. Dans 99,9%, vous aurez des classes DTO séparées dans ce cas et probablement beaucoup de différentes versions pour supporter les anciens clients. Peu importe où vous placez les Attributs DataMembers, car vous utilisez les DTO. Je ne prendrai pas la peine d'expliquer ce scénario, parce que les développeurs qui travaillent sur un tel système à grande échelle sont généralement assez expérimentés, et ils ne prennent pas la peine de lire SO.

+0

Quand il s'agit de sérialisation liée à la plate-forme, liée au type - alors oui! les champs représentent en effet l'état. Je pense 'BinaryFormatter' etc. ici. Cependant, en termes de données ** interopérables **, lorsque le type de réception est ** non ** identique (il pourrait être généré par mex/wsdl, ou pourrait être une plate-forme complètement différente), nous devrions avoir ** aucune connaissance ** de (ou dépendance sur) les champs. Oui, la validation reste importante, et il existe des mécanismes pour cela (et d'autres choses, comme les rappels). –

+0

En outre; le travail de sérialisation n'est * pas * simplement "la persistance de l'état de l'objet" - il le fait * de la manière qui correspond au protocole *. Pour BinaryFormatter, cela signifie (par defualt) "les champs", mais pour WCF ... pas tellement. La ** donnée ** n'est pas 'm_someValue' - la * donnée * est' SomeValue'. 'm_someValue' est un détail d'implémentation. Il y a des manières de manipuler le mapping (comme: using 'Name' sur le champ pour faire apparaître' m_someValue' comme 'SomeValue') –

+0

@MarcGravell Je suis d'accord avec vous sur l'interopérabilité, je pense à ce sujet en tant que un processus simple d'état persistant et restaurateur, mais c'est plus que ça. Ma réponse s'applique essentiellement à la situation où vous avez C# aux deux extrémités, et vous réutilisez les mêmes classes. Si nous prenons par exemple la situation où nous avons du code C# comme récepteur et du code PHP comme expéditeur, alors la situation est un peu différente, j'ai besoin de temps pour y réfléchir, que je pense que je mettrai à jour ma réponse. –

Questions connexes