Friend-Klassenäquivalent in C#

Abdul Mateen 12 Oktober 2023
  1. Friend-Klasse in C++
  2. Verwenden Sie das C#-Äquivalent der Friend-Klasse
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.

Verwandter Artikel - Csharp Class