2009-11-11 20 views
2

Je suis tombé sur une fonctionnalité de la résolution de la méthode C# que je n'avais pas remarquée auparavant. À savoir, lorsque j'implémente explicitement une interface qui supporte un setter, et que l'interface implicite n'offre qu'un ensemble protégé, le compilateur se replie sensiblement sur l'ensemble protégé quand je l'appelle. J'obtiens donc la plus grande partie de la commodité des propriétés implémentées automatiquement, mais je peux empêcher la modification accidentelle des champs par les clients qui ne devraient pas les modifier.Utilisation d'interfaces explicites pour empêcher la modification accidentelle de propriétés dans C#

À titre d'exemple,

virtual public DateTime CreatedOn { get; protected set; } 
virtual public DateTime? ModifiedOn { get; protected set; } 
#region IHaveUpdateDateFields Members 

DateTime IHaveUpdateDateFields.CreatedOn 
{ 
    get 
    { 
     return this.CreatedOn; 
    } 
    set 
    { 
     this.CreatedOn = value; 
    } 
} 

DateTime? IHaveUpdateDateFields.ModifiedOn 
{ 
    get 
    { 
     return this.ModifiedOn; 
    } 
    set 
    { 
     this.ModifiedOn = value; 
    } 
} 

Ensuite, mon modèle code contraignant ne définit pas par hasard la date, mais mon écouteur d'événement ORM peut vérifier les entités qui mettent en œuvre IHaveUpdateDateFields et fixent la date à laquelle persiste mon entité.

Mes questions sont les suivantes:

  1. Suis-je compter sur le comportement défini, ou suis-je garantis que tous les compilateurs C# résoudront les méthodes de cette façon? Je ne veux pas découvrir que la norme C# indique que ce type de résolution de méthode est indéfini et que, par exemple, un dépassement de pile horrifiant se produit lorsque je compile pour Mono.
  2. Existe-t-il une façon plus agréable (idéalement terser) de faire cela? Je pourrais avoir une interface ModelBinder-safe que je transmettrais à mon contrôleur, mais cela ne me semble pas me sauver du code et je ne pense pas que cela fournirait une approche aussi transparente pour minimiser la modification accidentelle des propriétés.

Répondre

3

Ceci est parfaitement bien défini; les implémentations d'interface explicites sont prioritaires lors de l'utilisation de l'interface, et la propriété regular prend effet autrement (y compris depuis le corps du get/set).

Quant à ce qui en fait le meilleur ... plus net que je peux offrir est de reformater pour le rendre moins bavard ...

DateTime IHaveUpdateDateFields.CreatedOn 
{ 
    get { return CreatedOn; } 
    set { CreatedOn = value; } 
} 

(note également que le this est implicite et redondante)

En aparté - la sécurité est seulement une commodité, pas une garantie ... les appelants externes peuvent toujours utiliser votre interface, et peuvent généralement (ab) utiliser la réflexion pour sauter des choses comme protected - ou même simplement définir les champs directement.

+0

Oui, c'est mon objectif ... Comme avec la plupart des constructions OO, je tente de protéger contre les erreurs, pas de fraude. L'idiome de l'ensemble protégé est utilisé pour les identifiants dans notre système, ce que bien sûr NHibernate utilise pour la réflexion. – JasonTrue