Friend-Klassenäquivalent in C#
In diesem Tutorial lernen Sie die Friend-Klassen-Äquivalente in C# kennen. Zuerst werden wir die Friend-Klasse und ihre Verwendung in der Programmierung anhand von C++-Beispielen diskutieren.
Als Nächstes sehen wir uns in Ermangelung eines Friend-Klassen-Äquivalents in C# die Alternativen an.
Friend-Klasse in C++
Ein wichtiges Programmiermerkmal, das hauptsächlich in der objektorientierten Programmierung angewendet wird, ist das Verbergen von Daten. Das Verbergen von Datenmembern außerhalb der Klasse bedeutet, dass die Datenmember nur innerhalb der Klasse aktualisiert werden können.
Daher können wir sagen, dass nur eine Klasse (die Datenelemente enthält) den Wert von Datenelementen ändern kann.
Durch das Ausblenden von Daten reduzieren wir den Testumfang, da wir die Klasse, die wir ändern, testen müssen. Keine andere Klasse kann auf die privaten Datenmitglieder einer Klasse zugreifen; Daher besteht keine Notwendigkeit, sie zu testen, wenn ihr Code nicht geändert wird.
Manchmal wird das Verbergen von Daten in langen und komplexen Codes ein wenig beeinträchtigt. Eine Klasse kann einige Funktionen oder Klassen als Freunde deklarieren.
Als Reaktion darauf können die “Freund”-Funktionen und die “Freund”-Klassen auf die privaten Datenelemente zugreifen.
Die Syntax der Freundschaft ist unten.
class ABC {
... friend class XYZ;
friend int change_data_member(int, char);
...
Die Klasse ABC
deklariert in Zeile 3 die Klasse XYZ
als Freund. Zeile 4 zeigt die Syntax zum Deklarieren einer friend
-Methode.
Hier deklariert die Klasse ABC
die Methode change_data_member
als friend
-Funktion.
Nach Erhalt des Freundschaftsflags von der Klasse ABC
kann jede Funktion der Klasse XYZ
auf die privaten Datenmitglieder der Klasse ABC
zugreifen.
Im Falle der Gewährung von Freundschaft zu einer Funktion hat die Freundschaft jedoch einen begrenzten Umfang. Nur die Freund
-Funktion (d. h. als Freund
deklariert) kann auf die privaten Daten von Mitgliedern der Freundschaft gewährenden Klasse zugreifen.
Sehen wir uns die Implementierung des Freundschaftskonzepts in C++ an.
#include <iostream>
using namespace std;
class ABC {
int privateMember;
public:
ABC(int privateMember) { this->privateMember = privateMember; }
friend int getPrivateMember(ABC &);
friend void setPrivateMember(ABC &, int);
};
int getPrivateMember(ABC &obj) { return obj.privateMember; }
void setPrivateMember(ABC &obj, int privateMember) {
obj.privateMember = privateMember;
}
int main() {
ABC abc(5);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
setPrivateMember(abc, 7);
cout << "Private Member: " << getPrivateMember(abc) << '\n';
return 0;
}
In diesem Code hat die Klasse ABC
den privaten Datenmember privateMember
. In den letzten beiden Zeilen des Klassenkörpers wird zwei Nicht-Klassenfunktionen Freundschaft gewährt: getPrivateMember
und setPrivateMember
.
Die Ausgabe dieses Codes ist unten.
Private Member: 5
Private Member: 7
Auf das private Datenelement wird sowohl für die Eingabe als auch für die Ausgabe zugegriffen. Es folgt ein Beispiel für eine Freund
-Klasse:
#include <iostream>
using namespace std;
class ABC {
int privateMember;
friend class DEF;
};
class DEF {
ABC abc;
public:
int getPrivateMember() { return abc.privateMember; }
void setPrivateMember(int privateMember) {
abc.privateMember = privateMember;
}
};
int main() {
DEF def;
def.setPrivateMember(12);
cout << "Private Member: " << def.getPrivateMember() << '\n';
return 0;
}
In der zweiten Zeile der Klasse ABC
wird der Klasse DEF
Freundschaft gewährt. Mit dem Freundschaftsstatus können die Methoden getPrivateMember
und setPrivateMember
der Klasse DEF
auf die privaten Mitglieder der Klasse ABC
zugreifen.
Die Ausgabe dieses Codes ist unten.
Private Member: 12
Dieses friend
-Funktions- oder friend
-Klassenkonzept ist in C++ verfügbar, nicht in C#. Es gibt jedoch einige Methoden, mit denen wir auf Nichtmitgliedsdatenfunktionen zugreifen können.
Verwenden Sie das C#-Äquivalent der Friend-Klasse
Es gibt verschiedene Methoden, um von einigen Nicht-Member-Funktionen in C# auf Datenmember einer beliebigen Klasse zuzugreifen. Lassen Sie uns das einzeln besprechen.
Verschachtelte Klassen verwenden
Das nächste C#-Äquivalent/Alternative einer C++-friend
-Klasse ist das Erstellen einer verschachtelten/inneren Klasse. Eine verschachtelte Klasse kann auf die privaten Datenelemente einer äußeren Klasse zugreifen.
Das folgende Beispiel erstellt die Klasse Inner_class
als verschachtelte Klasse zu Outer_class
. Innerhalb des Gültigkeitsbereichs einer enthaltenden Klasse kann die Inner_class
auf private Mitglieder der Outer_class
zugreifen und dadurch die Klasse friend
imitieren.
using System;
public class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
Im obigen Code haben wir eine äußere Klasse und eine innere Klasse. Die Variable privateMember
ist ein privates Mitglied der äußeren Klasse.
Innerhalb der Inner_class
greifen wir auf das private Datenelement zu, das privateMember
der äußeren Klasse ist.
Als nächstes haben wir die Klasse Driver
, wo wir ein Objekt der Inner_class
erstellt haben. Mit dem Objekt Inner_class
rufen wir die innerClassFunction
innerhalb der Inner_class
auf.
Ausgang:
Private Member: 5
Obwohl der obige Code ohne Probleme erstellt und ausgeführt wird, ist es dennoch vorzuziehen, die Inner_class
von der Outer_class
getrennt zu platzieren, indem das partielle Klassenkonzept verwendet wird, wie im folgenden Beispiel angegeben.
using System;
public partial class Outer_class {
int privateMember;
Outer_class(int privateMember) {
this.privateMember = privateMember;
}
}
public partial class Outer_class {
public class Inner_class {
public void innerClassFunction() {
Outer_class obj = new Outer_class(5);
Console.WriteLine("Private Member: " + obj.privateMember);
}
}
}
public class Driver {
static public void Main() {
Outer_class.Inner_class obj = new Outer_class.Inner_class();
obj.innerClassFunction();
}
}
In der zweiten partiellen Klassendefinition von Outer_class
haben wir eine Funktion innerClassFunction
. Diese innerClassFunction
-Methode erzeugt ein Objekt der äußeren Klasse.
Wir übergeben 5
als Argument für den Konstruktorparameter, während wir ein Outer_class
-Objekt erstellen. Dieser Konstruktorparameter wird zum Wert des Datenmembers in der ersten Teildefinition der äußeren Klasse, wie in der Ausgabe unten zu sehen ist.
Private Member: 5
Teilklassen sind in großen Projekten wichtig, in denen mehrere Personen unterschiedliche Teile einer Klasse schreiben.
Hier nutzen wir diese partielle Klassenoption und schreiben Inner_class
als weiteren Teil der äußeren Klasse hinein. Dieses partielle Schema kann die partiellen Einheiten getrennt halten, aber wir können diese als eine einzelne Einheit verwenden.
Der Hauptvorteil dieses Schemas besteht darin, dass die eigentliche Klassendefinition nicht demjenigen offengelegt wird, der die Inner_class
-Definition schreibt.
Reflexionsobjekte
Mit den Objekten von Reflection
können wir Informationen zum Laufzeittyp erhalten.
Wir können Reflection
-Objekte verwenden, um die Type
-Informationen während der Programmausführung zu erhalten. Über den Namensraum System.Reflection
kann auf die Metadaten eines Programms in der Ausführung zugegriffen werden.
Die System.Reflection
liefert nützliche Informationen zur Laufzeit und hilft, dem Programm verschiedene Typen, Werte und Klassenobjekte hinzuzufügen.
Außerdem können wir die Methoden mit dem Namensraum System.Reflection
in den Griff bekommen und die privaten Methoden der Klasse testen.
Auf diese Weise können wir private Methoden der Klasse aufrufen. Daher kann es die Klasse Freund
replizieren.
Nehmen wir zum Beispiel die folgende Klasse mit einer privaten Methode callable_fun()
an.
public class Class1 {
private char callable_fun() {
return 'C';
}
}
Um die private Funktion callable_fun
zu testen, müssen wir den folgenden Code schreiben:
using System.Reflection;
public class Driver {
static public void Main() {
Class1 c = new Class1();
Type class1Type = c.GetType();
MethodInfo callMeMethod =
class1Type.GetMethod("callable_fun", BindingFlags.Instance | BindingFlags.NonPublic);
char result = (char)callMeMethod.Invoke(c, null);
Console.WriteLine("Output:" + result);
}
}
Die Ausgabe dieses Codes ist unten.
Output:C
Wenn Sie das Visual Studio Team System verwenden, können Sie in diesem Fall VS dazu bringen, automatisch eine Proxy-Klasse mit privaten Accessoren zu generieren, indem Sie mit der rechten Maustaste auf die Methode klicken und Create Unit Tests...
auswählen.
Verwenden der Klasse InternalsVisibleToAttribute
Diese Klasse trägt dazu bei, die Sichtbarkeit einer bestimmten Assembly für die Typen zu verbessern, die normalerweise nur in der aktuellen Assembly sichtbar sind.
// Syntax
[System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
public sealed class InternalsVisibleToAttribute : Attribute
Wenn wir zwei unsignierte Assemblys haben, hilft die Klasse InternalsVisibleToAttribute
beim Zugriff auf das private Member einer unsignierten Assembly durch eine andere unsignierte Assembly. Als Argument wird der Name einer Assembly (mit dem Namen der Klasse/Assembly friend
) übergeben.
Sehen wir uns als Nächstes ein Beispiel an, in dem InternalsVisibleToAttribute
verwendet wird, um auf das private Member einer anderen unsignierten Assembly zuzugreifen. Hier greift SecondClass
auf das private Member von FirstClass
zu.
Siehe den folgenden Code.
using System;
using System.Runtime.CompilerServices;
using Utilities.Example;
[assembly:InternalsVisibleToAttribute("FirstClass")]
namespace Utilities.Example {
public class FirstClass {
internal static int InnerMethod(int x) {
return x * x;
}
}
}
Das folgende Beispiel liefert den Quellcode für die Assembly SecondClass
:
public class SecondClass {
public static void Main() {
Console.WriteLine(FirstClass.InnerMethod(10));
}
}
Die Ausgabe dieses Codes ist 100
.
Wenn wir signierte Assemblys haben, sind der Verzeichnispfad und die Dateinamenerweiterung nicht erforderlich.
Das nächste Beispiel verwendet InternalsVisibleToAttribute
, um die private Methode namens innerMethod
in einer signierten Assembly aufzurufen, die für eine andere signierte Assembly sichtbar ist. Es definiert die Klasse FirstClass
, die eine interne Methode innerMethod
enthält.
using System;
using System.IO;
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo(
"Friend_Assembly, PublicKey=002400000480000094" + "0000000602000000240000525341310004000" +
"001000100bf8c25fcd44838d87e245ab35bf7" + "3ba2615707feea295709559b3de903fb95a93" +
"3d2729967c3184a97d7b84c7547cd87e435b5" + "6bdf8621bcb62b59c00c88bd83aa62c4fcdd4" +
"712da72eec2533dc00f8529c3a0bbb4103282" + "f0d894d5f34e9f0103c473dce9f4b457a5dee" +
"fd8f920d8681ed6dfcb0a81e96bd9b176525a" + "26e0b3")]
public class FirstClass {
internal static int innerMethod(int x) {
return x * x;
}
}
Angenommen, das folgende Beispiel wird in eine Assembly mit starkem Namen namens Friend_Assembly
kompiliert. Die innere Methode in FirstClass
ruft erfolgreich die innerMethod
auf, obwohl die Methode intern in FirstClass
ist.
public class SecondClass {
public static void Main() {
int result = FirstClass.innerMethod(10);
Console.WriteLine(result);
}
}
Die Ausgabe dieses Codes ist wiederum 100
.
Wir haben verschiedene Äquivalente der C++-Klasse friend
in C# vorgestellt. Leser können alle nach ihren Anforderungen verwenden.