Pourquoi C # ne fournit-il pas le mot clé «ami» de style C ++?

Le mot clé ami C ++ permet à une class A de désigner la class B comme amie. Cela permet à la Class B d’accéder aux membres private / protected de la class A

Je n’ai jamais lu quoi que ce soit sur les raisons pour lesquelles C # (et VB.NET) ont été omis. La plupart des réponses à cette question de StackOverflow semblent indiquer que c’est une partie utile de C ++ et qu’il y a de bonnes raisons de l’utiliser. Dans mon expérience je devrais être d’accord.

Une autre question me semble être 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 nestedes, elles ne semblent pas aussi élégantes que l’utilisation du mot clé friend .

Le livre original Design Patterns l’ utilise régulièrement dans ses exemples.

Donc, en résumé, pourquoi un friend est-il absent de C #, et quelle est la meilleure façon de le simuler en C #?

(D’ailleurs, le mot-clé internal n’est pas la même chose, il permet à toutes les classes de l’assembly entier d’accéder internal membres internal , alors friend vous permet de donner à une certaine classe un access complet à exactement une autre classe)

    Avoir des amis dans la programmation est plus ou moins considéré comme “sale” et facile à abuser. Il brise les relations entre les classes et mine certains atsortingbuts fondamentaux d’un langage OO.

    Cela étant dit, c’est une fonctionnalité intéressante et je l’ai souvent utilisée en C ++. et aimerait l’utiliser en C # aussi. Mais je parie qu’en raison de l ‘”OOness” pur 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

    Sur une note sérieuse: interne n’est pas aussi bon qu’un ami mais ça fait le travail. Rappelez-vous qu’il est rare que vous dissortingbuiez votre code à des développeurs tiers sans passer par une DLL. aussi longtemps que vous et votre équipe êtes au courant des classes internes et de leur utilisation, ça devrait aller.

    EDIT Permettez-moi de préciser comment le mot-clé ami mine la POO.

    Les variables et méthodes privées et protégées constituent peut-être l’une des parties les plus importantes de la POO. L’idée selon laquelle les objects peuvent contenir des données ou une logique qu’ils peuvent uniquement 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 ne peut pas gérer. En utilisant friend, vous associez les implémentations de deux classes – ce qui est bien pire si vous venez de coupler leur interface.

    Sur une note latérale. Utiliser friend ne consiste pas à violer l’encapsulation, mais au contraire à la faire respecter. À l’instar des accesseurs + mutateurs, de la surcharge des opérateurs, de l’inheritance public, du downcasting, etc. , il est souvent mal utilisé, mais cela ne signifie pas que le mot clé n’a pas, ou pire, un mauvais objective.

    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 ++.

    Pour info, une autre chose similaire mais non identique 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 access “interne” aux types / membres dans l’assemblage d’origine.

    Vous devriez pouvoir accomplir le même genre de choses que “friend” est utilisé en C ++ en utilisant des interfaces en C #. Il vous oblige à définir explicitement quels membres sont passés entre les deux classes, ce qui représente un travail supplémentaire, mais peut également faciliter la compréhension du code.

    Si quelqu’un a un exemple d’utilisation raisonnable de “ami” qui ne peut pas être simulé en utilisant des interfaces, veuillez le partager! J’aimerais mieux comprendre les différences entre C ++ et C #.

    Avec un friend un concepteur C ++ a un contrôle précis sur les membres privés * auxquels ils sont exposés. Mais, il est forcé 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 peut exposer un seul membre privé. Mais, il sera exposé à toutes les classes de l’assemblage.

    Généralement, un concepteur ne souhaite exposer que quelques méthodes privées à quelques autres classes. Par exemple, dans un modèle de fabrique de classes, il peut être souhaitable que la classe C1 ne soit instanciée que par l’usine de classe CF1. Par conséquent, la classe C1 peut avoir un constructeur protégé et une fabrique de classes friend CF1.

    Comme vous pouvez le voir, nous avons deux dimensions le long desquelles l’encapsulation peut être violée. friend viole sur une dimension, internal fait sur l’autre. Lequel est une violation plus grave du concept d’encapsulation? Dur à dire. Mais ce serait bien d’avoir à la fois un friend et un internal disponible. En outre, le troisième type de mot-clé, qui serait utilisé par membre (comme internal ) et qui spécifie la classe cible (comme friend ), serait un bon ajout à ces deux.

    * Pour être bref, j’utiliserai “privé” au lieu de “privé et / ou protégé”.

    – Nick

    Vous pouvez vous rapprocher de C ++ “friend” avec le mot-clé C # “internal” .

    Friend est extrêmement utile pour écrire un test unitaire.

    Bien que le coût de la pollution de la déclaration de votre classe soit un peu limité, c’est aussi un rappel forcé du compilateur sur les tests susceptibles de prendre en compte 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 en fait des amis des éléments qu’ils créent qui ont un constructeur protégé. Plus précisément, c’était lorsque j’avais une seule usine chargée de créer des objects de rendu correspondants pour les objects de création de rapports, en les rendant dans un environnement donné. Dans ce cas, vous avez un sharepoint connaissance unique sur la relation entre les classes de rédacteur de rapport (éléments tels que les blocs d’image, les bandes de mise en forme, les en-têtes de page, etc.) et leurs objects de rendu correspondants.

    Ce n’est en fait pas un problème avec C #. C’est une limitation fondamentale en IL. C # est limité par ceci, de même que tout autre langage .Net qui cherche à être vérifiable. Cette limitation inclut également les classes gérées définies en C ++ / CLI ( section Spéc. 20.5 ).

    Cela dit, je pense que Nelson a une bonne explication de la raison pour laquelle c’est une mauvaise chose.

    C # manque le mot-clé “ami” pour la même raison que sa destruction déterministe manquante. Les conventions changeantes incitent les gens à se sentir intelligents, comme si leurs nouvelles méthodes é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 imprévoyant que d’autres déclarations non qualifiées comme “ne pas utiliser gotos” ou “Linux est meilleur que Windows”.

    Le mot-clé “ami” associé à 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” ne permet pas un tel ciblage, et utiliser “protected” pour obtenir l’effet avec l’inheritance est gênant s’il n’y a pas vraiment de relation conceptuelle “est une”.

    En fait, C # donne la possibilité d’obtenir le même comportement en mode POO pur sans mots spéciaux – ce sont des interfaces privées.

    En ce qui concerne la question Qu’est-ce que l’équivalent en C # d’un ami? a été marqué comme duplicata à cet article et personne ne propose vraiment une bonne réalisation – je vais montrer la réponse sur les deux questions ici.

    L’idée principale prenait de là: Qu’est-ce qu’une interface privée?

    Disons que nous avons besoin d’une classe capable de gérer des instances d’une autre classe et d’y appeler des méthodes spéciales. Nous ne voulons pas donner la possibilité d’appeler cette méthode à d’autres classes. C’est exactement la même chose que le mot clé ami c ++ dans le monde c ++.

    Je pense qu’un bon exemple dans la pratique réelle pourrait être le modèle de machine à états complets où certains contrôleurs mettent à jour l’object d’état actuel et basculent vers un autre object d’état si nécessaire.

    Vous pourriez:

    • La manière la plus simple et la plus efficace de rendre la méthode Update () publique – espérons que tout le monde comprend pourquoi c’est mauvais.
    • La prochaine façon est de le marquer comme interne. C’est assez bien si vous mettez vos classes dans un autre assemblage, mais même alors, chaque classe de cet assemblage pourrait appeler chaque méthode interne.
    • Utilisez une interface privée / protégée – et j’ai suivi cette voie.

    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(ssortingng[] args) { //it's impossible to write Controller.IState p = new StateBase(); //Controller.IState is hidden StateBase p = new StateBase(); //p.Update(); //is not accessible } } 

    Eh bien, qu’en est-il de l’inheritance?

    Nous devons utiliser la technique décrite dans la section Étant donné que les implémentations de membres d’interface explicite ne peuvent pas être déclarées virtuelles et marquer IState comme protégé pour donner la possibilité de dériver du contrôleur également.

    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 la classe Héritage du lancer de contrôleur : ControllerTest.cs

     class ControllerTest: Controller { public ControllerTest() { IState testObj = new PlayerIdleState(); testObj.Update(); } } 

    J’espère couvrir tous les cas et ma réponse a été utile.

    Arrêtez de faire des excuses pour cette limitation. ami est mauvais, mais interne est bon? ils sont 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 appliquer le paradigme d’encapsulation? vous devez donc écrire des méthodes d’accesseur et maintenant quoi? comment êtes-vous censé arrêter 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’une des meilleures langues que j’ai vues, mais trouver des excuses ridicules pour les fonctionnalités manquantes n’aide personne. En C ++, le système simple d’événement / délégué me manque, reflet (+ dé / sérialisation automatique) et foreach, mais en C # je manque la surcharge de l’opérateur (oui, continuez à me dire que vous n’en avez pas besoin), parameters par défaut, const cela ne peut pas être contourné, inheritance multiple (oui, continuez à me dire que vous n’en aviez pas besoin et les interfaces étaient un remplacement suffisant) et possibilité de supprimer une instance de la mémoire (non, ce n’est bricoleur)

    Il y a l’InternalsVisibleToAtsortingbute depuis .Net 3 mais je suppose qu’ils ne l’ont ajouté que pour tester les assemblages après la montée des tests unitaires. Je ne peux pas voir beaucoup d’autres raisons de l’utiliser.

    Cela fonctionne au niveau de l’assemblage mais cela fait le travail là où c’est interne; c’est-à-dire où vous souhaitez dissortingbuer un assembly mais souhaitez qu’un autre assembly non dissortingbué y ait un access privilégié.

    À juste titre, ils exigent que l’assemblée des amis soit forte, afin d’éviter que quelqu’un crée un semblant d’ami à côté de votre ensemble protégé.

    J’ai lu beaucoup de commentaires intelligents sur le mot-clé “ami” et je suis d’accord avec son utilité, mais je pense que ce mot-clé “interne” est moins utile, et ils sont toujours mauvais pour la programmation OO pure.

    Ce que nous avons? (en disant “ami” je dis aussi à propos de “interne”)

    • utiliser “ami” rend le code moins pur en ce qui concerne oo?
    • Oui;

    • ne pas utiliser “ami” rend le code mieux?

    • non, nous avons encore besoin de faire des relations privées entre les classes, et nous ne pouvons le faire que si nous cassons notre belle encapsulation, donc ce n’est pas bon, je peux dire encore plus mal que d’utiliser “ami”.

    Utiliser friend crée des problèmes locaux, ne pas l’utiliser pose des problèmes aux utilisateurs de bibliothèques de codes.

    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 object la plus commune et la plus pure. Vous pouvez ouvrir l’access à n’importe quelle méthode de votre choix pour n’importe quelle classe.

    Je pense que cela a quelque chose à voir avec le modèle de compilation C # – la construction de IL avec la compilation JIT à l’exécution. c’est-à-dire: la même raison pour laquelle les génériques C # sont fondamentalement différents des génériques C ++.

    Si vous travaillez avec C ++ et que vous trouvez votre mot-clé ami, c’est une indication très forte que vous avez un problème de conception, car pourquoi une classe a besoin d’accéder aux membres privés d’une autre classe?

    vous pouvez le garder privé et utiliser la reflection pour appeler des fonctions. Le framework de test peut le faire si vous lui demandez de tester une fonction privée

    J’avais l’habitude d’utiliser régulièrement un ami, 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 pour atteindre le but avec le moins de code.

    Un exemple concret est la création d’assemblages d’interface fournissant une interface de communication à d’autres logiciels. Généralement, il existe quelques classes lourdes qui traitent la complexité du protocole et les particularités des pairs et fournissent un modèle relativement simple de connexion / lecture / écriture / transmission / déconnexion impliquant le transfert de messages et de notifications entre l’application client et l’assembly. Ces messages / notifications doivent être regroupés dans des classes. Les atsortingbuts doivent généralement être manipulés par le logiciel de protocole car ils sont leur créateur, mais beaucoup de choses doivent restr en lecture seule dans le monde extérieur.

    Il est tout à fait ridicule de déclarer que le protocole ou la classe “créateur” constitue une violation de la POO pour avoir un access intime à toutes les classes créées. La classe créasortingce a dû mordre chaque bit de données au fur et à mesure. Ce que j’ai trouvé le plus important est de minimiser toutes les lignes de code supplémentaires de BS auxquelles conduit le modèle «OOP for OOP’s Sake». Des spaghettis supplémentaires ne font que créer plus d’insectes.

    Les utilisateurs savent-ils que vous pouvez appliquer le mot-clé interne au niveau de l’atsortingbut, 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 l’émuler dans une classe C #: 1. déclarez la classe C # publique 2. déclarez tous les atsortingbuts / propriétés / méthodes protégés en C ++ et donc accessibles aux amis interne en C # 3. créer des propriétés en lecture seule pour un access public à tous les atsortingbuts et propriétés internes

    Je suis d’accord que ce n’est pas 100% identique à l’ami, et le test unitaire est un exemple très précieux du besoin de quelque chose comme ami (comme le code d’enregistrement de l’parsingur de protocole). Cependant, interne fournit l’exposition aux classes que vous voulez exposer, et [InternalVisibleTo ()] gère le rest – semble être né spécifiquement pour le test unitaire.

    En ce qui concerne friend “être meilleur parce que vous pouvez contrôler explicitement quelles classes ont access” – qu’est-ce qu’un groupe de classes maléfiques suspectes font en premier lieu dans la même assemblée? Partitionnez vos assemblages!

    L’amitié peut être simulée en séparant les interfaces et les implémentations. L’idée est la suivante: ” Exiger une instance concrète mais restreindre l’access à la 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 que ItsMeYourFriend() est uniquement public, la classe Friend peut y accéder, car personne d’autre ne peut obtenir une instance concrète de la classe Friend . Il possède un constructeur privé, tandis que la méthode factory New() 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.

    Certains ont suggéré que les choses peuvent devenir incontrôlables en utilisant un ami. Je suis d’accord, mais cela n’en diminue pas l’utilité. Je ne suis pas certain que l’ami blesse nécessairement le paradigme OO, pas plus que de rendre tous les membres de votre classe publics. 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 le recours à des amis dans des cas spécifiques où cela se comprend. Je pense que dans certains cas, l’exposition interne est trop importante. Pourquoi exposer une classe ou une méthode à tout dans l’assemblage?

    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’erreurs de l’utilisateur final pour l’application dans une méthode protégée.

     ReportError("Uh Oh!"); 

    J’ai maintenant un contrôle utilisateur contenu dans la page. Je souhaite que le contrôle utilisateur puisse appeler les méthodes de rapport d’erreurs dans la page.

     MyBasePage bp = Page as MyBasePage; bp.ReportError("Uh Oh"); 

    Il ne peut pas le faire si la méthode ReportError est protégée. Je peux le rendre interne, mais il est exposé à tout code dans l’assemblage. Je veux juste qu’il soit exposé aux éléments de l’interface utilisateur qui font partie de la page en cours (y compris les contrôles enfants). Plus précisément, je souhaite que ma classe de contrôle de base définisse exactement les mêmes méthodes de rapport d’erreur et appelle simplement les méthodes de la page de base.

     protected void ReportError(ssortingng str) { MyBasePage bp = Page as MyBasePage; bp.ReportError(str); } 

    Je crois que quelque chose comme ami pourrait être utile et implémenté dans le langage sans rendre le langage moins “OO”, peut-être en tant qu’atsortingbuts, afin que vous puissiez avoir des classes ou des méthodes spécifiques, permettant au développeur de fournir access 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, peut-être avoir quelque chose comme ce qui suit (on peut argumenter la sémantique, mais j’essaie simplement de faire comprendre l’idée):

     class BasePage { [Friend(BaseControl.ReportError(ssortingng)] protected void ReportError(ssortingng str) { } } class BaseControl { protected void ReportError(ssortingng str) { MyBasePage bp = Page as MyBasePage; bp.ReportError(str); } } 

    À mon avis, le concept d’ami ne présente 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 vous 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 à l’interne ou au public.

    Bsd

    Il a été dit que, les amis fait mal à OOness pure. 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 en C ++. J’aimerais avoir des champs / méthodes auxquels ma classe d’ami peut accéder, mais je ne les aimerais pas pour accéder à TOUS mes champs / méthodes. Comme dans la vraie vie, je laissais mes amis accéder à mon réfrigérateur personnel mais je ne les laissais pas accéder à mon compte bancaire.

    On peut l’implémenter 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(ssortingng s) { // some code } } class FriendClass { public void SomeMethod() { C1 c = new C1(); c.MyMethod(this, 5.5, 3); } } 

    That will of course generate a comstackr warning, and will hurt the intellisense. But it will do the work.

    On a side note, I think that a confident programmer should do the testing unit without accessing the private members. this is quite out of the scope, but try to read about TDD. however, if you still want to do so (having c++ like friends) try something like

     #if UNIT_TESTING public #else private #endif double x; 

    so you write all your code without defining UNIT_TESTING and when you want to do the unit testing you add #define UNIT_TESTING to the first line of the file(and write all the code that do the unit testing under #if UNIT_TESTING). That should be handled carefully.

    Since I think that unit testing is a bad example for the use of friends, I’d give an example why I think friends can be good. Suppose you have a breaking system (class). With use, the breaking system get worn out and need to get renovated. Now, you want that only a licensed mechanic would fix it. To make the example less sortingvial I’d say that the mechanic would use his personal (private) screwdriver to fix it. That’s why mechanic class should be friend of breakingSystem class.

    The friendship may also be simulated by using “agents” – some inner classes. 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 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. } } 

    It could be alot simpler when used for access only to static members. Benefits for such implementation is that all the types are declared in the inner scope of friendship classes and, unlike interfaces, it allows static members to be accessed.

    I will answer only “How” question.

    There are so many answers here, however I would like to propose kind of “design pattern” to achieve that feature. I will use simple language mechanism, which includes:

    • Interfaces
    • Nested class

    For example we have 2 main classes: Student and University. Student has GPA which only university allowed to access. 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 ssortingng Name { get; set; } PrivateData privateData; public Student(ssortingng 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(); 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(ssortingng[] 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(); } 

    Fields that ALL classes can access them are public .

    Fields that NOT all other classes can access them are private .

    (if the fields belongs to (declared inside) base class, then they are protected instead)

    Fields that only their owner class can access them are private , and have no properties and get set methods.

    Fields that only their owner class and some other classes can access them are private and each has special private get and set methods, and public share methods.

    The some other classes that can also access these fields will have some private fields of delegate types and special public direct methods.

    Exemple:

     class A { private int integer; // In the meantime, it seems that only A can access this integer private int GetInteger() // Get method is not public, because we don't want all other classes to use this integer { return this.integer; } private void SetInteger(int value) //Set method is not public, because we don't want all other classes to modify this integer { this.integer = value; } public void Share(ref B b) //I use the 'ref' keyword, to prevent the 'null' value in this argument, but if you call this method in a constructor of B, or in one of its methods, so you will have to remove the 'ref' keyword, or make overload of the same method without the 'ref' keyword, because 'ref this' is not allowed { b.DirectGetIntegerAndSetIntegerMethods(this.GetInteger, this.SetInteger); } public void PrintInteger() { Console.WriteLine(this.integer); } } class B //This class can access the 'integer' of A too, ie the 'integer' of A is "public" only for B { private Func GetInteger; //Will execute the 'GetInteger' method of A private Action SetInteger; //Will execute the 'SetInteger' method of A public void DirectGetIntegerAndSetIntegerMethods(Func getInteger, Action setInteger) { this.GetInteger = getInteger; this.SetInteger = setInteger; } public void Increment() { this.SetInteger(this.GetInteger() + 1); } } class Program { static void Main(ssortingng[] args) { A a = new A(); //Created new instance of A, and also new Int32 was initialized inside it and set to its default value 0, but unable to get or set its value, only just print it. a.PrintInteger(); B b = new B(); //Must create new instance of B, in order to change the integer of A to some value. For example, I will use b, to change the integer of a to 3 a.Share(ref b); //But before the change, I must tell 'a' to share his GetInteger and SetInteger methods to 'b', so 'b' will also be able execute them, through his Func and Action delegates, because GetInteger and SetInteger methods of A are private and cannot be executed directly. for (int i = 0; i < 3; i++) b.Increment(); a.PrintInteger(); //Print the integer of 'a' again after change. //Now the output of the console is: //0 //3 } } 

    You have to know that using the 'friend' keyword of the C++ is to allow some classes to share their private members to some other classes directly .

    Because of that the 'friend' keyword doesn't exist in C#, classes have no way to share their private fields to some other classes directly , but there is way to simulate it indeed as I shown above.

    Do you know that the 'friend' keyword of C++ also can allow in the implementation of some functions to access the private members of some instances of some classes types?

    The answer is yes and I will show you how to simulate this too in C#:

    Exemple:

     using System; using System.Reflection; //New namespace is added using System.Diagnostics; //Another new namespace is added too class Person { private readonly StackTrace st = new StackTrace(); //Helper object private readonly MethodInfo mi = typeof(Program).GetMethod("Foo"); //The MethodInfo of the method Foo, which will be declared and defined in class Program later, is the friend of the class Person //Both objects above are readonly, because they always reference the same objects that they were initialized with. private ssortingng name_of_his_dog; //Only Person can access this field private ssortingng GetTheNameOfHisDog() //Not public so that not all methods will be able to get this name { return this.name_of_his_dog; } private void SetTheNameOfHisDog(ssortingng new_name) //Not public so that not all methods will be able to set this name { this.name_of_his_dog = new_name; } public Func ShareTheGetTheNameOfHisDogMethod() //Returns null, if the previous method that called this method is not friend of this class Person { if (this.st.GetFrame(1).GetMethod() == this.mi) return this.GetTheNameOfHisDog; return null; } public Action ShareTheSetTheNameOfHisDogMethod() //Same as above { if (this.st.GetFrame(1).GetMethod() == this.mi) return this.SetTheNameOfHisDog; return null; } public void PrintTheNameOfHisDog() { Console.WriteLine(this.name_of_his_dog); } } class Program { static void Main(ssortingng[] args) { Person person = Foo(); person.PrintTheNameOfHisDog(); Func getTheNameOfHisDog = person.ShareTheGetTheNameOfHisDogMethod(); //returns null, Main is not friend of Person Action setTheNameOfHisDog = person.ShareTheSetTheNameOfHisDogMethod(); //returns null too, for the same reason setTheNameOfHisDog("Pointer"); //Runtime Error: Object reference not set to an instance of an object Console.WriteLine(getTheNameOfHisDog()); //Same runtime error //Output before runtime error: //Boxer //Boxer } public static Person Foo() //Only this method can get and set the name of the dog that belongs to the person { Person person = new Person(); Func getTheNameOfHisDog = person.ShareTheGetTheNameOfHisDogMethod(); Action setTheNameOfHisDog = person.ShareTheSetTheNameOfHisDogMethod(); setTheNameOfHisDog("Boxer"); Console.WriteLine(getTheNameOfHisDog()); return person; } } 

    I must admit that before I posted this code, I didn't know how to find out the MethodInfo of the previous method that called the current method, but Firas Assaad's answer helped me, thanks to him too.

    Comment trouver la méthode appelée méthode actuelle?

    He suggested to use the System.Diagnostics.StackTrace class

    Hope that you got my idea, and that helps and answers your question.

    I didn't find this answer anywhere in the internet, I thought about this idea by myself using my brain.