2010-11-22 3 views
27
class TestClass 
{ 
    private string _privateString = "hello"; 
    void ChangeData() 
    { 
     TestClass otherTestClass = new TestClass(); 
     otherTestClass._privateString = "world"; 
    } 
} 

Ce code compile en C# et l'équivalent fonctionne en PHP, mais quelqu'un peut-il expliquer la raison pour laquelle otherTestClass._privateString peut être changé ici?Pourquoi une variable de membre privé peut-elle être modifiée par instance de classe?

J'aurais pensé qu'une instance d'une classe ne devrait en aucun cas pouvoir changer une variable membre privée, et qu'essayer d'accéder à otherTestClass._privateString donnerait une erreur 'inaccessible en raison d'un niveau de protection'.

Ceci n'est cependant pas le cas, alors pourquoi l'instanciation d'un objet dans sa propre classe vous permet-elle d'accéder aux membres privés? Et devrait-il, cela ne rompt pas l'encapsulation dans une certaine mesure? Ou est-ce que je manque quelque chose d'évident?

  • (Je ne demande pas si la conception de classe ci-dessus est une bonne pratique, se demandant à peu près la théorie derrière.)

Modifier - Merci pour les réponses et commentaires. Pour clarifier, je suis également intéressé de savoir si être capable de faire cela est considéré comme une caractéristique positive, ou si c'est un compromis nécessaire pour une meilleure vérification de compilation/clarté du code/parce que la plupart des autres langues le font de cette manière. Il me semble idéalement que le compilateur vous prévienne ou vous prévienne, mais je suis loin d'être un concepteur de langage. Tout exemple de comment cela pourrait vous permettre de faire quelque chose d'utile (sans violer l'encapsulation) qui serait autrement difficile ou impossible serait génial.

+0

BTW: Vous pouvez rendre 'ChangeData()' même 'static' et vous pourrez toujours accéder aux membres privés. – ulrichb

+0

@ulrichb - Il est important de noter pour l'OP que vous ne pouvez pas utiliser le mot clé 'this' pour accéder aux membres privés si' ChangeData() 'est' static'. – TheCloudlessSky

+1

En tant qu'exemple d'un langage différent - dans Ruby, public est le même, mais privé signifie «seulement accessible par la même instance» et protégé signifie «uniquement accessible depuis la même classe». L'héritage n'a rien à voir là-bas. – Tesserex

Répondre

35

Les membres privés sont accessibles à tout code dans le texte du programme de cette classe (y compris dans les types imbriqués). Cela n'a rien à voir avec l'instance de la classe à laquelle vous avez affaire.

Je ne crois pas que cela viole l'encapsulation - l'API est toujours séparée de l'implémentation, mais l'implémentation "sait" sur elle-même, quelle que soit l'instance qu'elle regarde.

Je crois que dans d'autres langages ce n'est pas comment l'accessibilité fonctionne, mais c'est certainement pour C# et Java. (Java a des règles légèrement différentes sur ce qui peut accéder aux membres privés, mais le code traduit pour ce que vous avez écrit fonctionnerait toujours.)

+3

L'implémentation de l'accessibilité au niveau de l'instance nécessiterait une vérification de l'exécution pour chaque accès à la variable membre, alors que ce modèle peut être vérifié lors de la compilation. –

+1

@James: Eh bien, pas nécessairement.Vous * pourriez * exiger que les membres privés soient uniquement disponibles via la référence "this". Ce serait hideux, mais possible. –

+1

J'ajouterais à la réponse de Jon que ce type de contrôle d'accès permet aux opérateurs n-aire tels que l'égalité d'être facilement écrit. Il serait beaucoup plus difficile d'implémenter l'opérateur d'égalité si aucune instance n'avait accès aux autres membres privés. –

9

Ceci est dû au fait que C# applique la confidentialité au niveau de la classe et non la confidentialité au niveau de l'objet.

La plupart des langages grand public appliquent la même politique, c'est-à-dire C#, C++ et Java. Je pense que la raison en est:

1) parce que les développeurs sont habitués à ce genre de politique; 2) parce que l'intimité au niveau de l'objet deviendrait beaucoup trop fastidieuse en échange de très peu d'avantages.

+0

Je ne crois pas qu'il y aurait Je pense qu'il serait fastidieux d'avoir des méthodes getter pour la valeur des membres de chaque classe, par exemple, car cela irait à l'encontre de l'encapsulation car vous pouvez également exposer des membres privés à d'autres classes! – Simone

+0

@ miket2e Essayez d'implémenter un constructeur de copie ou une simple fonction Equals avec un niveau de confidentialité au niveau de l'objet.C'est simple dans le C# actuel: return this._somePrivateField.Eq uals (other._somePrivateField) - Si vous pouvez accéder à other._somePrivateField, comment implémenteriez-vous une telle fonctionnalité sans ajouter de getters publics? –

+1

@MichaelStum: L'un des avantages d'avoir des champs instance-private ou instance-protected est que cela rend clair que les classes dérivées peuvent réutiliser ces champs sans enfreindre le principe de substitution de Liskov. Sinon, une telle réutilisation peut entraîner des violations LSP. Quelque chose comme 'Equals' peut être implémenté en ayant une méthode' Equals' privée-classe qui accepte le contenu de l'autre objet (soit comme un ensemble de paramètres discrets, ou en utilisant un type protégé par une classe), et ayant le public 'Equals 'la méthode d'un objet passe son état à la méthode 'Protected' de l'autre. – supercat

Questions connexes