Perché C # non fornisce la parola chiave “amico” in stile C ++?

La parola chiave friend C ++ consente ad una class A di designare la class B come sua amica. Ciò consente alla Class B di accedere ai membri private / protected di class A

Non ho mai letto nulla sul motivo per cui questo è stato lasciato fuori da C # (e VB.NET). La maggior parte delle risposte a questa precedente domanda di StackOverflow sembrano dire che è una parte utile del C ++ e ci sono buoni motivi per usarlo. Nella mia esperienza dovrei essere d’accordo.

Un’altra domanda mi sembra davvero chiedere come fare qualcosa di simile ad un friend in un’applicazione C #. Mentre le risposte generalmente ruotano attorno a classi annidate, non sembra abbastanza elegante come usare la parola chiave friend .

Il libro Design Pattern originale lo utilizza regolarmente nei suoi esempi.

Quindi, in sintesi, perché manca l’ friend di C #, e qual è il modo (o i modi) di “best practice” di simularlo in C #?

(A proposito, la parola chiave internal non è la stessa cosa, consente a tutte le classi all’interno dell’intero assembly di accedere internal membri internal , mentre l’ friend consente di dare a una determinata class un accesso completo a esattamente un’altra class)

Avere amici in programmazione è più o meno considerato “sporco” e facile da abusare. Rompe le relazioni tra classi e mina alcuni attributi fondamentali di un linguaggio OO.

Detto questo, è una bella funzionalità e l’ho usata molte volte in C ++; e vorrei usarlo anche in C #. Ma ho scommesso a causa della “pura” OOness di C # (rispetto allo pseudo OOness di C ++) MS ha deciso che, poiché Java non ha nessuna parola chiave C #, non dovrebbe neanche (scherzando);))

Su una nota seria: interno non è buono come amico, ma ottiene il lavoro fatto. Ricorda che è raro che tu stia distribuendo il tuo codice a sviluppatori di terze parti non tramite una DLL; finché tu e il tuo team siete a conoscenza delle classi interne e del loro utilizzo, dovreste stare bene.

EDIT Permettetemi di chiarire in che modo la parola chiave friend mina OOP.

Le variabili e i metodi privati ​​e protetti sono forse una delle parti più importanti di OOP. L’idea che gli oggetti possano contenere dati o logica che solo loro possono utilizzare consente di scrivere l’implementazione della funzionalità indipendentemente dal proprio ambiente e che il proprio ambiente non può alterare le informazioni di stato che non è adatto a gestire. Usando l’amico si stanno unendo le implementazioni di due classi insieme, il che è molto peggio se si accoppiasse la propria interfaccia.

In una nota a margine. Usare l’amico non significa violare l’incapsulamento, ma al contrario è metterlo in pratica. Come accessors + mutator, overloading degli operatori, ereditarietà pubblica, downcasting, ecc. , È spesso utilizzato in modo improprio, ma ciò non significa che la parola chiave non abbia o, peggio, un cattivo scopo.

Vedi il messaggio di Konrad Rudolph nell’altro thread, o se preferisci vedere la voce pertinente nelle FAQ del C ++.

Per informazioni, un’altra cosa correlata ma non la stessa in .NET è [InternalsVisibleTo] , che consente a un assembly di designare un altro assembly (come un assembly unit test) che (effettivamente) ha un accesso “interno” ai tipi / membri nell’assemblaggio originale.

Dovresti essere in grado di realizzare lo stesso tipo di cose per cui “amico” è usato in C ++ usando le interfacce in C #. Richiede di definire in modo esplicito quali membri vengono passati tra le due classi, il che è un lavoro extra ma può anche rendere il codice più facile da capire.

Se qualcuno ha un esempio di un uso ragionevole di “amico” che non può essere simulato usando le interfacce, per favore condividi! Mi piacerebbe capire meglio le differenze tra C ++ e C #.

Con l’ friend un designer C ++ ha un controllo preciso su cui i membri privati ​​* sono esposti. Ma è costretto ad esporre tutti i membri privati.

Con un designer C # internal ha un controllo preciso sul set di membri privati ​​che espone. Ovviamente, può esporre solo un singolo membro privato. Ma, verrà esposto a tutte le classi nell’assemblea.

In genere, un designer desidera esporre solo alcuni metodi privati ​​per selezionare poche altre classi. Ad esempio, in un modello di fabbrica di class si può desiderare che la class C1 sia istanziata solo dalla fabbrica di class CF1. Pertanto la class C1 può avere un costruttore protetto e una fabbrica di class amico CF1.

Come puoi vedere, abbiamo 2 dimensioni lungo le quali l’incapsulamento può essere violato. friend infrange lungo una dimensione, l’ internal fa lungo l’altro. Quale è una breccia peggiore nel concetto di incapsulamento? Difficile da dire. Ma sarebbe bello avere sia l’ friend che l’ internal disponibili. Inoltre, una buona aggiunta a questi due sarebbe il terzo tipo di parola chiave, che verrebbe utilizzato per membro membro per membro (come internal ) e specifica la class di destinazione (come friend ).

* Per brevità userò “privato” anziché “privato e / o protetto”.

– Nick

Puoi avvicinarti al “amico” C ++ con la parola chiave C # “interna” .

L’amico è estremamente utile quando si scrive un test unitario.

Anche se ciò ha un costo di inquinare leggermente la dichiarazione della class, è anche un promemoria imposto dal compilatore di quali test in realtà potrebbero interessare lo stato interno della class.

Un idioma molto utile e pulito che ho trovato è quando ho lezioni in fabbrica, rendendole amiche degli oggetti che creano e che hanno un costruttore protetto. Più specificamente, questo è stato quando ho avuto un singolo factory responsabile della creazione di oggetti di rendering corrispondenti per gli oggetti di report writer, il rendering in un determinato ambiente. In questo caso si ha un singolo punto di conoscenza sulla relazione tra le classi di report-writer (cose come blocchi immagine, bande di layout, intestazioni di pagina ecc.) E i corrispondenti oggetti di rendering.

Questo non è in realtà un problema con C #. È un limite fondamentale in IL. C # è limitato da questo, come qualsiasi altro linguaggio .Net che cerca di essere verificabile. Questa limitazione include anche classi gestite definite in C ++ / CLI ( Spec section 20.5 ).

Detto questo, penso che Nelson abbia una buona spiegazione del perché questa sia una brutta cosa.

C # manca la parola chiave “amico” per lo stesso motivo per cui manca la distruzione deterministica. Cambiare le convenzioni fa sentire le persone intelligenti, come se i loro nuovi modi fossero superiori ai vecchi modi di qualcun altro. Si tratta di orgoglio.

Dire che “le classi di amici sono cattive” è miope come altre affermazioni non qualificate come “non usare gotos” o “Linux è meglio di Windows”.

La parola chiave “amico” combinata con una class proxy è un ottimo modo per esporre solo determinate parti di una class a specifiche altre classi. Una class proxy può fungere da barriera fidata contro tutte le altre classi. “pubblico” non consente alcun tipo di targeting e l’utilizzo di “protetto” per ottenere l’effetto con l’ereditarietà è scomodo se non esiste una relazione “è una” concettuale.

In effetti, C # offre la possibilità di ottenere lo stesso comportamento in puro modo OOP senza parole speciali: si tratta di interfacce private.

Per quanto riguarda la domanda Qual è l’equivalente C # di un amico? è stato contrassegnato come duplicato di questo articolo e nessuno vi propone davvero una buona realizzazione – mostrerò risposta su entrambe le domande qui.

L’idea principale stava prendendo da qui: cos’è un’interfaccia privata?

Diciamo che abbiamo bisogno di qualche class che possa gestire istanze di altre classi e chiamare su di esse alcuni metodi speciali. Non vogliamo dare la possibilità di chiamare questo metodo ad altre classi. Questa è esattamente la stessa cosa che un amico c ++ fa parola chiave nel mondo c ++.

Penso che un buon esempio nella pratica reale potrebbe essere il pattern di Full State Machine in cui alcuni controller aggiornano l’object dello stato corrente e passano a un altro object di stato quando necessario.

Potresti:

  • Il modo più semplice e peggiore per rendere pubblico il metodo Update (): spero che tutti capiscano perché è male.
  • Il prossimo modo è contrassegnarlo come interno. È abbastanza buono se metti le tue classi su un altro assembly, ma anche allora ogni class in quell’assembly potrebbe chiamare ogni metodo interno.
  • Usa l’interfaccia privata / protetta – e ho seguito questa strada.

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 StateBase(); //Controller.IState is hidden StateBase p = new StateBase(); //p.Update(); //is not accessible } } 

Bene, per quanto riguarda l’ereditarietà?

Abbiamo bisogno di utilizzare la tecnica descritta in Poiché le implementazioni esplicite dei membri dell’interfaccia non possono essere dichiarate virtuali e contrassegnare IState come protetto per dare la possibilità di derivare anche dal 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()"); } } 

E infine un esempio su come testare l’ereditarietà del controller di class: ControllerTest.cs

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

Spero di coprire tutti i casi e la mia risposta è stata utile.

Smetti di inventare scuse per questa limitazione. l’amico è cattivo, ma interno è buono? sono la stessa cosa, solo quell’amico ti dà un controllo più preciso su chi è autorizzato ad accedere e chi no.

Questo è per rafforzare il paradigma di incapsulamento? quindi devi scrivere metodi di accesso e ora cosa? come si dovrebbe impedire a tutti (tranne ai metodi della class B) di chiamare questi metodi? non puoi, perché non puoi controllare neanche questo, a causa della mancanza di un “amico”.

Nessun linguaggio di programmazione è perfetto. C # è una delle migliori lingue che ho visto, ma fare scuse stupide per le funzionalità mancanti non aiuta nessuno. In C ++, mi manca l’easy event / delegate system, reflection (+ de / serializzazione automatica) e foreach, ma in C # mi manca l’overloading dell’operatore (sì, continua a dirmi che non ti serviva), i parametri di default, un const che non può essere aggirato, ereditarietà multipla (sì, continua a dirmi che non ne hai avuto bisogno e le interfacce erano una sostituzione sufficiente) e la possibilità di decidere di eliminare un’istanza dalla memoria (no, questo non è terribilmente brutto a meno che tu non sia un riparatore)

Esiste l’InternalsVisibleToAttribute da .Net 3 ma sospetto che l’abbiano aggiunto solo per soddisfare gli assemblee dopo l’aumento dei test unitari. Non vedo molti altri motivi per usarlo.

Funziona a livello di assemblaggio, ma fa il lavoro dove non interno; ovvero, dove si desidera distribuire un assembly ma si desidera che un altro assembly non distribuito abbia accesso privilegiato ad esso.

Abbastanza giustamente richiedono che l’assemblea di amici sia forte per evitare che qualcuno crei un finto amico accanto all’assemblea protetta.

Ho letto molti commenti intelligenti sulla parola chiave “amico” e sono d’accordo su cosa sia utile, ma penso che la parola chiave “interna” sia meno utile, ed entrambi sono ancora negativi per la pura programmazione OO.

Cosa abbiamo? (dicendo di “amico” dico anche di “interno”)

  • sta usando “amico” rende il codice meno puro riguardo a oo?
  • sì;

  • non sta usando “amico” rende il codice migliore?

  • no, abbiamo ancora bisogno di fare delle relazioni private tra le classi, e possiamo farlo solo se rompiamo il nostro bellissimo incapsulamento, quindi non va bene, posso dire che è ancora più malvagio che usare “amico”.

L’uso di friend fa alcuni problemi locali, non usarlo crea problemi agli utenti di code-library.

la soluzione comune per il linguaggio di programmazione che vedo in questo modo:

 // c++ style class Foo { public_for Bar: void addBar(Bar *bar) { } public: private: protected: }; // c# class Foo { public_for Bar void addBar(Bar bar) { } } 

Cosa ne pensi? Penso che sia la soluzione orientata agli oggetti più comune e pura. Puoi aprire l’accesso a qualsiasi metodo tu scelga per qualsiasi class desideri.

Sospetto che abbia qualcosa a che fare con il modello di compilazione C # – la costruzione di IL JIT che lo compila in fase di runtime. cioè: la stessa ragione per cui i generici C # sono fondamentalmente diversi dai generici C ++.

Se stai lavorando con C ++ e trovi te stesso usando la parola chiave friend, è un’indicazione molto forte, che hai un problema di progettazione, perché perché una class ha bisogno di accedere ai membri privati ​​di un’altra class?

puoi mantenerlo privato e utilizzare la riflessione per chiamare le funzioni. Il framework di test può farlo se lo si chiede per testare una funzione privata

Ho usato regolarmente l’amico, e non penso che sia una violazione di OOP o un segno di qualsiasi difetto di progettazione. Ci sono molti posti in cui è il mezzo più efficace per la corretta fine con la minor quantità di codice.

Un esempio concreto è quando si creano assembly di interfaccia che forniscono un’interfaccia di comunicazione ad altri software. Generalmente esistono alcune classi pesanti che gestiscono la complessità delle peculiarità del protocollo e dei peer e forniscono un modello di connessione / lettura / scrittura / inoltro / disconnessione relativamente semplice che coinvolge messaggi di passaggio e notifiche tra l’app client e l’assembly. Questi messaggi / notifiche devono essere racchiusi in classi. Gli attributi generalmente devono essere manipolati dal software di protocollo in quanto è il loro creatore, ma molte cose devono rimanere di sola lettura per il mondo esterno.

È semplicemente stupido dichiarare che si tratta di una violazione di OOP perché la class protocollo / “creatore” abbia un accesso intimo a tutte le classi create – la class creator ha dovuto masticare un po ‘ogni bit di dati. Quello che ho trovato più importante è ridurre al minimo tutte le linee di codice BS aggiuntive che il modello “OOP per OOP’s Sake” porta in genere. Gli spaghetti extra fanno solo più insetti.

Le persone sanno che è ansible applicare la parola chiave interna a livello di attributo, proprietà e metodo? Non è solo per la dichiarazione della class di alto livello (anche se molti esempi sembrano dimostrarlo).

Se hai una class C ++ che usa la parola chiave friend e vuoi emularla in una class C #: 1. dichiara la class C # public 2. dichiara tutti gli attributi / proprietà / metodi che sono protetti in C ++ e quindi accessibili agli amici come internal in C # 3. crea proprietà di sola lettura per l’accesso pubblico a tutti gli attributi e proprietà interni

Sono d’accordo che non è al 100% lo stesso di un amico, e il test di unità è un esempio molto utile del bisogno di qualcosa come amico (come il codice di registrazione dell’analizzatore di protocollo). Tuttavia, l’interno fornisce l’esposizione alle classi che si desidera avere l’esposizione e [InternalVisibleTo ()] gestisce il resto – sembra che sia nato specificamente per il test dell’unità.

Per quanto riguarda l’amico “essere migliori perché puoi controllare in modo esplicito quali classi hanno accesso” – che diamine sono un sacco di classi maligne sospette che fanno nello stesso assembly in primo luogo? Partizione tuoi assemblee!

L’amicizia può essere simulata separando le interfacce e le implementazioni. L’idea è: ” Richiedere un’istanza concreta ma limitare l’accesso alla costruzione di quell’istanza “.

Per esempio

 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) { } } 

Nonostante ItsMeYourFriend() sia di pubblico ItsMeYourFriend() solo la class Friend può accedervi, poiché nessun altro può ottenere un’istanza concreta della class Friend . Ha un costruttore privato, mentre il metodo Factory New() restituisce un’interfaccia.

Vedi il mio articolo Amici e membri dell’interfaccia interna gratuitamente con la codifica delle interfacce per i dettagli.

Alcuni hanno suggerito che le cose possono andare fuori controllo usando un amico. Sarei d’accordo, ma ciò non diminuisce la sua utilità. Non sono sicuro che l’amico danneggi necessariamente il paradigma OO più che rendere pubblici tutti i membri della tua class. Sicuramente la lingua ti permetterà di rendere pubblici tutti i tuoi membri, ma è un programmatore disciplinato che evita quel tipo di schema di progettazione. Allo stesso modo un programmatore disciplinato riserverebbe l’uso di un amico per casi specifici in cui ha senso. Mi sento troppo esposto in alcuni casi. Perché esporre una class o un metodo a tutto ciò che fa parte dell’assemblaggio?

Ho una pagina ASP.NET che eredita la mia stessa pagina di base, che a sua volta eredita System.Web.UI.Page. In questa pagina, ho un codice che gestisce la segnalazione degli errori degli utenti finali per l’applicazione in un metodo protetto

 ReportError("Uh Oh!"); 

Ora ho un controllo utente contenuto nella pagina. Voglio che il controllo utente sia in grado di chiamare i metodi di segnalazione degli errori nella pagina.

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

Non può farlo se il metodo ReportError è protetto. Posso renderlo interno, ma è esposto a qualsiasi codice nell’assieme. Voglio solo che sia esposto agli elementi dell’interfaccia utente che fanno parte della pagina corrente (inclusi i controlli figlio). Più specificamente, voglio che la mia class di controllo di base definisca esattamente gli stessi metodi di segnalazione degli errori e chiami semplicemente i metodi nella pagina di base.

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

Credo che qualcosa come l’amico possa essere utile e implementato nella lingua senza rendere la lingua meno “OO”, forse come attributi, in modo che tu possa avere classi o metodi essere amici per classi o metodi specifici, permettendo allo sviluppatore di fornire molto accesso specifico. Forse qualcosa come … (pseudo codice)

 [Friend(B)] class A { AMethod() { } [Friend(C)] ACMethod() { } } class B { BMethod() { A.AMethod() } } class C { CMethod() { A.ACMethod() } } 

Nel caso del mio esempio precedente forse ho qualcosa di simile al seguente (si può argomentare la semantica, ma sto solo cercando di far passare l’idea):

 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); } } 

Per come la vedo io, il concetto di amicizia non ha più rischi di renderlo pubblico, o di creare metodi o proprietà pubbliche per accedere ai membri. Se qualcosa di amico consente un altro livello di granularità nell’accessibilità dei dati e consente di restringere tale accessibilità piuttosto che ampliarla con interni o pubblici.

Bsd

È stato affermato che gli amici feriscono la pura OOness. Che sono d’accordo.

È stato anche affermato che gli amici aiutano l’incapsulamento, che anch’io sono d’accordo.

Penso che l’amicizia dovrebbe essere aggiunta alla metodologia OO, ma non esattamente come in C ++. Mi piacerebbe avere alcuni campi / metodi a cui la mia class di amici può accedere, ma NON mi piacerebbe che accedessero a TUTTI i miei campi / metodi. Come nella vita reale, permettevo ai miei amici di accedere al mio frigorifero personale ma non permettevo loro di accedere al mio conto in banca.

Si può attuare ciò come segue

  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); } } 

That will of course generate a compiler 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 trivial 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 classs. Considera il seguente esempio:

 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 classs 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:

  • interfacce
  • Nested class

For example we have 2 main classs: Student and University. Student has GPA which only university allowed to access. Ecco il codice:

 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(); 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(); } 

Fields that ALL classs can access them are public .

Fields that NOT all other classs 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 classs can access them are private and each has special private get and set methods, and public share methods.

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

Esempio:

 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 classs to use this integer { return this.integer; } private void SetInteger(int value) //Set method is not public, because we don't want all other classs 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(string[] 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 classs to share their private members to some other classs directly .

Because of that the 'friend' keyword doesn't exist in C#, classs have no way to share their private fields to some other classs 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 classs types?

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

Esempio:

 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 string name_of_his_dog; //Only Person can access this field private string GetTheNameOfHisDog() //Not public so that not all methods will be able to get this name { return this.name_of_his_dog; } private void SetTheNameOfHisDog(string 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(string[] 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.

Come posso trovare il metodo che ha chiamato il metodo corrente?

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.