Le mot clé ami C ++ permet class A
à a de désigner class B
comme son ami. Cela permet Class B
d'accéder aux private
/ protected
membres de class A
.
Je n'ai jamais rien lu sur les raisons pour lesquelles cela a été laissé en dehors de C # (et VB.NET). La plupart des réponses à cette question précédente de StackOverflow semblent indiquer que c'est une partie utile de C ++ et qu'il y a de bonnes raisons de l'utiliser. D'après mon expérience, je devrais être d'accord.
Une autre question me semble être vraiment de savoir comment faire quelque chose de similaire friend
dans une application C #. Bien que les réponses tournent généralement autour de classes imbriquées, cela ne semble pas aussi élégant que l'utilisation du friend
mot - clé.
Le livre original de Design Patterns l' utilise régulièrement tout au long de ses exemples.
Donc, en résumé, pourquoi est friend
absent de C #, et quelle est la ou les meilleures pratiques pour le simuler en C #?
(À propos, le internal
mot-clé n'est pas la même chose, il permet à toutes les classes de l'assemblage entier d'accéder aux internal
membres, tout en friend
vous permet de donner à une certaine classe un accès complet à exactement une autre classe)
Réponses:
Avoir des amis dans la programmation est plus ou moins considéré comme «sale» et facile à abuser. Il rompt les relations entre les classes et sape certains attributs fondamentaux d'un langage OO.
Cela étant dit, c'est une fonctionnalité intéressante et je l'ai souvent utilisée moi-même en C ++; et aimerait l'utiliser également en C #. Mais je parie qu'à cause de l'OOness "pure" de C # (comparé au pseudo OOness de C ++) MS a décidé que parce que Java n'a pas de mot-clé ami, C # ne devrait pas non plus (je plaisante;))
Sur une note sérieuse: l'interne n'est pas aussi bon qu'un ami, mais il fait le travail. N'oubliez pas qu'il est rare que vous distribuiez votre code à des développeurs tiers sans passer par une DLL; donc tant que vous et votre équipe êtes au courant des classes internes et de leur utilisation, tout va bien.
EDIT Permettez-moi de clarifier comment le mot-clé ami sape la POO.
Les variables et méthodes privées et protégées sont peut-être l'une des parties les plus importantes de la POO. L'idée que les objets peuvent contenir des données ou une logique qu'ils seuls peuvent utiliser vous permet d'écrire votre implémentation de fonctionnalités indépendamment de votre environnement - et que votre environnement ne peut pas modifier les informations d'état qu'il n'est pas adapté à gérer. En utilisant friend, vous couplez les implémentations de deux classes ensemble - ce qui est bien pire si vous venez de coupler leur interface.
la source
friend
ne permet pas aux classes ou fonctions arbitraires d'accéder aux membres privés. Il permet aux fonctions ou classes spécifiques marquées comme ami de le faire. La classe propriétaire du membre privé en contrôle toujours l'accès à 100%. Vous pourriez aussi bien argumenter que les méthodes des membres publics. Les deux garantissent que les méthodes spécifiquement répertoriées dans la classe ont accès aux membres privés de la classe.Sur une note latérale. Utiliser un ami ne consiste pas à violer l'encapsulation, mais au contraire à l'appliquer. Comme les accesseurs + mutateurs, la surcharge des opérateurs, l'héritage public, le downcasting, etc. , il est souvent mal utilisé, mais cela ne signifie pas que le mot-clé n'a pas, ou pire, un mauvais but.
Voir le message de Konrad Rudolph dans l 'autre thread, ou si vous préférez voir l' entrée correspondante dans la FAQ C ++.
la source
friend
lui donne accès à TOUS vos membres privés, même si vous n'avez besoin que de le laisser définir l'un d'entre eux. Il y a un argument fort à faire valoir que rendre des champs disponibles à une autre classe qui n'en a pas besoin compte comme "violer l'encapsulation". Il y a des endroits en C ++ où c'est nécessaire (surcharger les opérateurs), mais il y a un compromis d'encapsulation qui doit être soigneusement considéré. Il semble que les concepteurs C # aient estimé que le compromis n'en valait pas la peine.Pour info, une autre chose liée mais pas tout à fait la même dans .NET est
[InternalsVisibleTo]
, qui permet à un assembly de désigner un autre assembly (tel qu'un assembly de test unitaire) qui a (effectivement) un accès "interne" aux types / membres dans l'assemblage d'origine.la source
Vous devriez être en mesure d'accomplir le même genre de choses pour lesquelles «ami» est utilisé en C ++ en utilisant des interfaces en C #. Cela vous oblige à définir explicitement quels membres sont passés entre les deux classes, ce qui est un travail supplémentaire mais peut également rendre le code plus facile à comprendre.
Si quelqu'un a un exemple d'utilisation raisonnable de "ami" qui ne peut pas être simulé à l'aide d'interfaces, partagez-le! J'aimerais mieux comprendre les différences entre C ++ et C #.
la source
Avec
friend
un concepteur C ++, il a un contrôle précis sur les personnes auxquelles les membres privés * sont exposés. Mais, il est obligé d'exposer chacun des membres privés.Avec
internal
un concepteur C # a un contrôle précis sur l'ensemble des membres privés qu'il expose. De toute évidence, il ne peut exposer qu'un seul membre privé. Mais, il sera exposé à toutes les classes de l'assembly.En règle générale, un concepteur souhaite exposer uniquement quelques méthodes privées à quelques autres classes sélectionnées. Par exemple, dans un modèle de fabrique de classes, il peut être souhaitable que la classe C1 soit instanciée uniquement par la fabrique de classes CF1. Par conséquent, la classe C1 peut avoir un constructeur protégé et une usine de classe ami CF1.
Comme vous pouvez le voir, nous avons 2 dimensions selon lesquelles l'encapsulation peut être violée.
friend
le brise le long d'une dimension, leinternal
fait le long de l'autre. Laquelle est la pire violation du concept d'encapsulation? Dur à dire. Mais ce serait bien d'avoir les deuxfriend
etinternal
disponibles. De plus, un bon ajout à ces deux serait le 3ème type de mot-clé, qui serait utilisé membre par membre (commeinternal
) et spécifie la classe cible (commefriend
).* Par souci de concision, j'utiliserai "privé" au lieu de "privé et / ou protégé".
- Pseudo
la source
En fait, C # donne la possibilité d'obtenir le même comportement en pure POO sans mots spéciaux - ce sont des interfaces privées.
En ce qui concerne la question Quel est l'équivalent C # de friend? a été marqué comme duplicata de cet article et personne là-bas ne propose une très bonne réalisation - je vais montrer la réponse aux deux questions ici.
L'idée principale partait d'ici: qu'est-ce qu'une interface privée?
Disons que nous avons besoin d'une classe qui pourrait gérer les instances d'une autre classe et y appeler des méthodes spéciales. Nous ne voulons pas donner la possibilité d'appeler ces méthodes à d'autres classes. C'est exactement la même chose que le mot-clé friend c ++ fait dans le monde c ++.
Je pense qu'un bon exemple dans la pratique réelle pourrait être le modèle Full State Machine où un contrôleur met à jour l'objet d'état actuel et passe à un autre objet d'état si nécessaire.
Vous pourriez:
Controller.cs
public class Controller { private interface IState { void Update(); } public class StateBase : IState { void IState.Update() { } } public Controller() { //it's only way call Update is to cast obj to IState IState obj = new StateBase(); obj.Update(); } }
Program.cs
class Program { static void Main(string[] args) { //it's impossible to write Controller.IState p = new Controller.StateBase(); //Controller.IState is hidden var p = new Controller.StateBase(); //p.Update(); //is not accessible } }
Eh bien, qu'en est-il de l'héritage?
Nous devons utiliser la technique décrite dans Puisque les implémentations de membres d'interface explicites ne peuvent pas être déclarées virtuelles et marquer IState comme protégé pour donner la possibilité de dériver également de Controller.
Controller.cs
public class Controller { protected interface IState { void Update(); } public class StateBase : IState { void IState.Update() { OnUpdate(); } protected virtual void OnUpdate() { Console.WriteLine("StateBase.OnUpdate()"); } } public Controller() { IState obj = new PlayerIdleState(); obj.Update(); } }
PlayerIdleState.cs
public class PlayerIdleState: Controller.StateBase { protected override void OnUpdate() { base.OnUpdate(); Console.WriteLine("PlayerIdleState.OnUpdate()"); } }
Et enfin, exemple comment tester l'héritage de la classe Controller throw: ControllerTest.cs
class ControllerTest: Controller { public ControllerTest() { IState testObj = new PlayerIdleState(); testObj.Update(); } }
J'espère que je couvre tous les cas et ma réponse a été utile.
la source
Vous pouvez vous rapprocher de C ++ "friend" avec le mot clé C # "internal" .
la source
internal
cela a beaucoup plus de sens et offre un excellent compromis entre l'encapsulation et l'utilité. L'accès par défaut de Java est cependant encore meilleur.Friend est extrêmement utile lors de l'écriture d'un test unitaire.
Bien que cela entraîne une légère pollution de votre déclaration de classe, c'est aussi un rappel imposé par le compilateur de ce que les tests peuvent réellement se soucier de l'état interne de la classe.
Un idiome très utile et propre que j'ai trouvé est quand j'ai des classes d'usine, ce qui les rend amis des éléments qu'ils créent et qui ont un constructeur protégé. Plus précisément, c'était à l'époque où j'avais une seule usine chargée de créer des objets de rendu correspondants pour les objets de création de rapports, en effectuant un rendu dans un environnement donné. Dans ce cas, vous avez un seul point de connaissance sur la relation entre les classes de rédacteur de rapport (des éléments tels que des blocs d'image, des bandes de mise en page, des en-têtes de page, etc.) et leurs objets de rendu correspondants.
la source
C # manque le mot clé "friend" pour la même raison que sa destruction déterministe manquante. Changer les conventions permet aux gens de se sentir intelligents, comme si leurs nouvelles façons de faire étaient supérieures aux anciennes méthodes de quelqu'un d'autre. Tout est question de fierté.
Dire que «les classes d'amis sont mauvaises» est aussi à courte vue que d'autres déclarations non qualifiées comme «n'utilisez pas de gotos» ou «Linux est meilleur que Windows».
Le mot-clé "friend" combiné à une classe proxy est un excellent moyen d'exposer uniquement certaines parties d'une classe à d'autres classes spécifiques. Une classe proxy peut agir comme une barrière de confiance contre toutes les autres classes. "public" n'autorise aucun ciblage de ce type, et utiliser "protected" pour obtenir l'effet avec l'héritage est gênant s'il n'y a vraiment pas de relation conceptuelle "is a".
la source
Ce n'est en fait pas un problème avec C #. C'est une limitation fondamentale de l'IL. C # est limité par cela, comme tout autre langage .Net qui cherche à être vérifiable. Cette limitation inclut également les classes gérées définies dans C ++ / CLI ( Spec section 20.5 ).
Cela étant dit, je pense que Nelson a une bonne explication quant aux raisons pour lesquelles c'est une mauvaise chose.
la source
friend
ce n'est pas une mauvaise chose; au contraire, c'est bien mieux queinternal
. Et l'explication de Nelson est mauvaise et incorrecte.Arrêtez de chercher des excuses pour cette limitation. ami est mauvais, mais interne est-il bon? c'est la même chose, seul cet ami vous donne un contrôle plus précis sur qui est autorisé à accéder et qui ne l'est pas.
C'est pour renforcer le paradigme d'encapsulation? vous devez donc écrire des méthodes d'accesseur et maintenant quoi? comment êtes-vous censé empêcher tout le monde (sauf les méthodes de la classe B) d'appeler ces méthodes? vous ne pouvez pas, parce que vous ne pouvez pas contrôler cela non plus, à cause d'un "ami" manquant.
Aucun langage de programmation n'est parfait. C # est l'un des meilleurs langages que j'ai vus, mais trouver des excuses idiotes pour des fonctionnalités manquantes n'aide personne. En C ++, je manque le système d'événement / délégué facile, la réflexion (+ dés / sérialisation automatique) et foreach, mais en C # je manque la surcharge d'opérateur (oui, continuez à me dire que vous n'en aviez pas besoin), les paramètres par défaut, un const qui ne peut être contourné, l'héritage multiple (ouais, continuez à me dire que vous n'en aviez pas besoin et que les interfaces étaient un remplacement suffisant) et la possibilité de décider de supprimer une instance de la mémoire (non, ce n'est pas horriblement mauvais sauf si vous êtes un bricoleur)
la source
||
/&&
tout en les gardant en court-circuit. Les paramètres par défaut ont été ajoutés en C # 4.Je répondrai seulement à la question «Comment».
Il y a tellement de réponses ici, mais j'aimerais proposer une sorte de "modèle de conception" pour réaliser cette fonctionnalité. J'utiliserai un mécanisme de langage simple, qui comprend:
Par exemple, nous avons 2 classes principales: étudiant et universitaire. L'étudiant a GPA auquel seule l'université est autorisée à accéder. Voici le code:
public interface IStudentFriend { Student Stu { get; set; } double GetGPS(); } public class Student { // this is private member that I expose to friend only double GPS { get; set; } public string Name { get; set; } PrivateData privateData; public Student(string name, double gps) => (GPS, Name, privateData) = (gps, name, new PrivateData(this); // No one can instantiate this class, but Student // Calling it is possible via the IStudentFriend interface class PrivateData : IStudentFriend { public Student Stu { get; set; } public PrivateData(Student stu) => Stu = stu; public double GetGPS() => Stu.GPS; } // This is how I "mark" who is Students "friend" public void RegisterFriend(University friend) => friend.Register(privateData); } public class University { var studentsFriends = new List<IStudentFriend>(); public void Register(IStudentFriend friendMethod) => studentsFriends.Add(friendMethod); public void PrintAllStudentsGPS() { foreach (var stu in studentsFriends) Console.WriteLine($"{stu.Stu.Name}: stu.GetGPS()"); } } public static void Main(string[] args) { var Technion = new University(); var Alex = new Student("Alex", 98); var Jo = new Student("Jo", 91); Alex.RegisterFriend(Technion); Jo.RegisterFriend(Technion); Technion.PrintAllStudentsGPS(); Console.ReadLine(); }
la source
Il y a l'InternalsVisibleToAttribute depuis .Net 3 mais je soupçonne qu'ils l'ont seulement ajouté pour répondre aux assemblages de test après la montée des tests unitaires. Je ne vois pas beaucoup d'autres raisons de l'utiliser.
Cela fonctionne au niveau de l'assemblage, mais il fait le travail là où l'interne ne fonctionne pas; c'est-à-dire où vous souhaitez distribuer un assembly, mais souhaitez qu'un autre assembly non distribué y ait un accès privilégié.
À juste titre, ils exigent que l'assemblage ami soit doté d'une clé forte pour éviter que quelqu'un ne crée un prétendu ami aux côtés de votre assemblage protégé.
la source
J'ai lu de nombreux commentaires intelligents sur le mot-clé "ami" et je suis d'accord pour dire que c'est une chose utile, mais je pense que le mot-clé "interne" est moins utile, et ils sont tous les deux toujours mauvais pour la programmation OO pure.
Ce que nous avons? (en disant à propos de "ami", je dis aussi à propos de "interne")
Oui;
le fait de ne pas utiliser "ami" améliore-t-il le code?
Utiliser friend pose des problèmes locaux, ne pas l'utiliser crée des problèmes pour les utilisateurs de la bibliothèque de code.
la bonne solution commune pour le langage de programmation que je vois comme ceci:
// c++ style class Foo { public_for Bar: void addBar(Bar *bar) { } public: private: protected: }; // c# class Foo { public_for Bar void addBar(Bar bar) { } }
Qu'est-ce que tu en penses? Je pense que c'est la solution orientée objet la plus courante et la plus pure. Vous pouvez ouvrir l'accès de n'importe quelle méthode de votre choix à n'importe quelle classe de votre choix.
la source
Je soupçonne que cela a quelque chose à voir avec le modèle de compilation C # - construire IL le JIT en le compilant au moment de l'exécution. ie: la même raison pour laquelle les génériques C # sont fondamentalement différents des génériques C ++.
la source
vous pouvez le garder privé et utiliser la réflexion pour appeler des fonctions. Le framework de test peut le faire si vous lui demandez de tester une fonction privée
la source
J'utilisais régulièrement Friend, et je ne pense pas que ce soit une violation de la POO ou un signe de défaut de conception. Il y a plusieurs endroits où c'est le moyen le plus efficace d'arriver à la bonne fin avec le moins de code.
Un exemple concret est celui de la création d'assemblys d'interface qui fournissent une interface de communication à d'autres logiciels. Généralement, il existe quelques classes lourdes qui gèrent la complexité du protocole et des particularités des pairs, et fournissent un modèle de connexion / lecture / écriture / transfert / déconnexion relativement simple impliquant le passage de messages et de notifications entre l'application cliente et l'assembly. Ces messages / notifications doivent être enveloppés dans des classes. Les attributs doivent généralement être manipulés par le logiciel de protocole car il est leur créateur, mais beaucoup de choses doivent rester en lecture seule pour le monde extérieur.
Il est tout simplement ridicule de déclarer que c'est une violation de la POO pour que la classe protocol / "creator" ait un accès intime à toutes les classes créées - la classe creator a dû briser chaque bit de données en montant. Ce que j'ai trouvé le plus important est de minimiser toutes les lignes de code supplémentaires BS auxquelles le modèle "OOP for OOP's Sake" conduit habituellement. Les spaghettis supplémentaires font juste plus d'insectes.
Les gens savent-ils que vous pouvez appliquer le mot-clé interne au niveau de l'attribut, de la propriété et de la méthode? Ce n'est pas seulement pour la déclaration de classe de niveau supérieur (bien que la plupart des exemples semblent le montrer.)
Si vous avez une classe C ++ qui utilise le mot-clé friend et que vous souhaitez émuler cela dans une classe C #: 1. déclarez la classe C # public 2. déclarez tous les attributs / propriétés / méthodes qui sont protégés en C ++ et donc accessibles aux amis comme internal en C # 3. créer des propriétés en lecture seule pour l'accès public à tous les attributs et propriétés internes
Je suis d'accord que ce n'est pas à 100% la même chose qu'un ami, et le test unitaire est un exemple très précieux du besoin de quelque chose comme ami (tout comme le code de journalisation de l'analyseur de protocole). Cependant, internal fournit l'exposition aux classes que vous souhaitez exposer, et [InternalVisibleTo ()] gère le reste - il semble qu'il soit né spécifiquement pour le test unitaire.
En ce qui concerne l'ami "étant meilleur parce que vous pouvez contrôler explicitement quelles classes ont accès" - qu'est-ce que diable font un tas de classes perverses suspectes dans le même assemblage en premier lieu? Partitionnez vos assemblages!
la source
L'amitié peut être simulée en séparant les interfaces et les implémentations. L'idée est: " Exiger une instance concrète mais restreindre l'accès de construction de cette instance ".
Par exemple
interface IFriend { } class Friend : IFriend { public static IFriend New() { return new Friend(); } private Friend() { } private void CallTheBody() { var body = new Body(); body.ItsMeYourFriend(this); } } class Body { public void ItsMeYourFriend(Friend onlyAccess) { } }
En dépit du fait qu'elle
ItsMeYourFriend()
est publique, seule laFriend
classe peut y accéder, car personne d'autre ne peut obtenir une instance concrète de laFriend
classe. Elle a un constructeur privé, tandis que laNew()
méthode factory renvoie une interface.Voir mon article Amis et membres de l'interface interne sans frais avec le codage des interfaces pour plus de détails.
la source
Certains ont suggéré que les choses peuvent devenir incontrôlables en utilisant un ami. Je serais d'accord, mais cela n'en diminue pas l'utilité. Je ne suis pas certain que cet ami blesse nécessairement le paradigme OO pas plus que de rendre publics tous les membres de votre classe. Certes, le langage vous permettra de rendre tous vos membres publics, mais c'est un programmeur discipliné qui évite ce type de modèle de conception. De même, un programmeur discipliné réserverait l'utilisation d'un ami pour des cas spécifiques où cela a du sens. Je sens que l'intérieur expose trop dans certains cas. Pourquoi exposer une classe ou une méthode à tout dans l'assembly?
J'ai une page ASP.NET qui hérite de ma propre page de base, qui à son tour hérite de System.Web.UI.Page. Dans cette page, j'ai du code qui gère les rapports d'erreur de l'utilisateur final pour l'application dans une méthode protégée
ReportError("Uh Oh!");
Maintenant, j'ai un contrôle utilisateur qui est contenu dans la page. Je veux que le contrôle utilisateur puisse appeler les méthodes de rapport d'erreur dans la page.
MyBasePage bp = Page as MyBasePage; bp.ReportError("Uh Oh");
Il ne peut pas faire cela si la méthode ReportError est protégée. Je peux le rendre interne, mais il est exposé à n'importe quel code de l'assembly. Je veux juste qu'il soit exposé aux éléments de l'interface utilisateur qui font partie de la page actuelle (y compris les contrôles enfants). Plus précisément, je veux que ma classe de contrôle de base définisse exactement les mêmes méthodes de rapport d'erreurs et appelle simplement des méthodes dans la page de base.
protected void ReportError(string str) { MyBasePage bp = Page as MyBasePage; bp.ReportError(str); }
Je pense que quelque chose comme friend pourrait être utile et implémenté dans le langage sans rendre le langage moins "OO" comme, peut-être en tant qu'attributs, afin que vous puissiez avoir des classes ou des méthodes amis de classes ou de méthodes spécifiques, permettant au développeur de fournir très accès spécifique. Peut-être quelque chose comme ... (pseudo code)
[Friend(B)] class A { AMethod() { } [Friend(C)] ACMethod() { } } class B { BMethod() { A.AMethod() } } class C { CMethod() { A.ACMethod() } }
Dans le cas de mon exemple précédent, j'ai peut-être quelque chose comme ce qui suit (on peut discuter de la sémantique, mais j'essaie juste de faire passer l'idée):
class BasePage { [Friend(BaseControl.ReportError(string)] protected void ReportError(string str) { } } class BaseControl { protected void ReportError(string str) { MyBasePage bp = Page as MyBasePage; bp.ReportError(str); } }
À mon avis, le concept d'ami n'a pas plus de risque que de rendre les choses publiques ou de créer des méthodes ou des propriétés publiques pour accéder aux membres. Si quelque chose d'ami permet un autre niveau de granularité dans l'accessibilité des données et vous permet de restreindre cette accessibilité plutôt que de l'élargir avec interne ou public.
la source
Si vous travaillez avec C ++ et que vous vous trouvez en utilisant le mot-clé friend, c'est une indication très forte, que vous avez un problème de conception, car pourquoi diable une classe a besoin d'accéder aux membres privés d'une autre classe ??
la source
Bsd
Il a été déclaré que, les amis blessent la pure OOness. Ce que je suis d'accord.
Il a également été déclaré que les amis aident à l'encapsulation, ce que je suis également d'accord.
Je pense que l'amitié devrait être ajoutée à la méthodologie OO, mais pas tout à fait comme elle en C ++. J'aimerais avoir certains champs / méthodes auxquels ma classe d'amis peut accéder, mais je ne voudrais PAS qu'ils accèdent à TOUS mes champs / méthodes. Comme dans la vraie vie, je laisserais mes amis accéder à mon réfrigérateur personnel mais je ne les laisserais pas accéder à mon compte bancaire.
On peut mettre en œuvre cela comme suit
class C1 { private void MyMethod(double x, int i) { // some code } // the friend class would be able to call myMethod public void MyMethod(FriendClass F, double x, int i) { this.MyMethod(x, i); } //my friend class wouldn't have access to this method private void MyVeryPrivateMethod(string s) { // some code } } class FriendClass { public void SomeMethod() { C1 c = new C1(); c.MyMethod(this, 5.5, 3); } }
Cela générera bien sûr un avertissement du compilateur et endommagera l'intellisense. Mais cela fera le travail.
Sur une note latérale, je pense qu'un programmeur confiant devrait faire l'unité de test sans accéder aux membres privés. c'est tout à fait hors de portée, mais essayez de lire sur TDD. cependant, si vous voulez toujours le faire (avoir C ++ comme des amis), essayez quelque chose comme
#if UNIT_TESTING public #else private #endif double x;
donc vous écrivez tout votre code sans définir UNIT_TESTING et lorsque vous voulez faire le test unitaire vous ajoutez #define UNIT_TESTING à la première ligne du fichier (et écrivez tout le code qui fait le test unitaire sous #if UNIT_TESTING). Cela devrait être manipulé avec soin.
Puisque je pense que les tests unitaires sont un mauvais exemple pour l'utilisation d'amis, je donnerais un exemple pourquoi je pense que les amis peuvent être bons. Supposons que vous ayez un système de rupture (classe). Avec l'utilisation, le système de freinage s'use et doit être rénové. Maintenant, vous voulez que seul un mécanicien agréé le répare. Pour rendre l'exemple moins trivial, je dirais que le mécanicien utiliserait son tournevis personnel (privé) pour le réparer. C'est pourquoi la classe de mécanicien devrait être l'amie de la classe BreakSystem.
la source
c.MyMethod((FriendClass) null, 5.5, 3)
depuis n'importe quelle classe.L'amitié peut également être simulée en utilisant des «agents» - certaines classes internes. Prenons l'exemple suivant:
public class A // Class that contains private members { private class Accessor : B.BAgent // Implement accessor part of agent. { private A instance; // A instance for access to non-static members. static Accessor() { // Init static accessors. B.BAgent.ABuilder = Builder; B.BAgent.PrivateStaticAccessor = StaticAccessor; } // Init non-static accessors. internal override void PrivateMethodAccessor() { instance.SomePrivateMethod(); } // Agent constructor for non-static members. internal Accessor(A instance) { this.instance = instance; } private static A Builder() { return new A(); } private static void StaticAccessor() { A.PrivateStatic(); } } public A(B friend) { B.Friendship(new A.Accessor(this)); } private A() { } // Private constructor that should be accessed only from B. private void SomePrivateMethod() { } // Private method that should be accessible from B. private static void PrivateStatic() { } // ... and static private method. } public class B { // Agent for accessing A. internal abstract class BAgent { internal static Func<A> ABuilder; // Static members should be accessed only by delegates. internal static Action PrivateStaticAccessor; internal abstract void PrivateMethodAccessor(); // Non-static members may be accessed by delegates or by overrideable members. } internal static void Friendship(BAgent agent) { var a = BAgent.ABuilder(); // Access private constructor. BAgent.PrivateStaticAccessor(); // Access private static method. agent.PrivateMethodAccessor(); // Access private non-static member. } }
Cela pourrait être beaucoup plus simple lorsqu'il est utilisé pour accéder uniquement aux membres statiques. Les avantages d'une telle implémentation sont que tous les types sont déclarés dans la portée interne des classes d'amitié et, contrairement aux interfaces, cela permet d'accéder aux membres statiques.
la source