Generika: Verwenden Sie parametrisierte Typen, um mehrere Datentypen mit demselben Code zu betreiben. Verwenden Sie „parametrisierte Typen“, um Typen zu abstrahieren und eine flexible Wiederverwendung zu erreichen.
Beispielcode:
class PROgram
{
static void Main(string[] args)
{
int obj = 2;
Test
Console.WriteLine("int:" + test.obj);
string obj2 = "hello world";
Test
Console.WriteLine("String:" + test 1 . obj);
Console.Read();
}
}
class Test
{
public T obj;
public Test(T obj)
{
this.obj = obj;
}
}
Das Ausgabeergebnis ist:
int:2
String:hello world
Programmanalyse:
1. Test ist eine generische Klasse. T ist der generische Typ, der instanziiert werden soll. Wenn T als Typ int instanziiert wird, dann ist die Mitgliedsvariable obj vom Typ int. Wenn T als Typ string instanziiert wird, dann ist obj vom Typ string.
2. Je nach Typ zeigt das obige Programm unterschiedliche Werte an.
Generischer C#-Mechanismus:
Generische C#-Funktionen werden von CLR zur Laufzeit unterstützt: Generischer C#-Code verwendet spezielle Methoden beim Kompilieren in IL-Code und Metadaten. Zur Darstellung werden Platzhalter verwendet generische Typen und generische Operationen werden mithilfe proprietärer IL-Anweisungen unterstützt. Die eigentliche generische Instanziierungsarbeit erfolgt „auf Abruf“ während der JIT-Kompilierung.
Sehen Sie sich gerade die Metadaten der Main-Funktion im Code an
.method private hidebysig static void Main(string[] args) cil verwaltet
{
.entrypoint
// Codegröße 79 (0x4f)
.maxstack 2
.locals init ([0] int32 obj,
1)
il_0000: nop
il_0001: ldc.i4.2
il_0002: stloc.0
il_0003: ldloc: ldloc. .0
IL_0004: newobj-Instanz void class CSharpStudy1.Test`1
IL_0009: stloc.1
IL_000a: " ldstr "int:"
IL_000f: ldloc.1
IL_0010: ldfld !0 class CSharpStudy1.Test`1
IL_0015: box [mscorlib ]System.Int3 2
IL_001a: Call String [mscorlib]System.String::Concat(object,
🎜> IL_001f: Call void [mscorlib]System.Console::WriteLine(string )
IL_0024: nop
IL_0025: ldstr „Hallo Welt“
IL_002a: stloc.2
IL_002b: ldloc.2
IL_002c: newobj-Instanz, leere Klasse CSharpStudy1.Test`1
IL_0031: stloc.3
IL_0032: ldstr "String:"
IL_0037: ldloc.3
IL_0038: ldfld !0 class CSharpStudy1.Test`1& lt;string> : :obj
IL_003d: Call String [mscorlib]System.String::Concat(string,
String)
IL_0042: Call void [mscorlib]System.Console: : WriteLine(string)
IL_0047: nop
IL_0048: call int32 [mscorlib]System.Console::Read()
IL_004d: pop
IL_004 e : ret
} // end of method Program::Main
Werfen wir einen Blick auf die Metadaten des Konstruktors in der Testklasse
.method public hidebysig specialname rtspecialname
Instanz void .ctor(!T obj) cil verwaltet
{
// Codegröße 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: Aufrufinstanz void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007 : nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld !0 class ConsoleCSharpTest1.Test`1 ::obj
IL_000f: nop
IL_0010: ret
} // Ende der Methode Test`1::.ctor
1. Während einer Kompilierungsrunde generiert der Compiler nur die „generische Version“ des IL-Codes und der Metadaten für den Test
wird in den Testtyp-Metadaten 2 angezeigt. Wenn der JIT-Compiler während der JIT-Kompilierung zum ersten Mal auf Test
wird in der Hauptfunktion 3 angezeigt. CLR generiert den gleichen Code für alle generischen Typen, deren Typparameter „Referenztypen“ sind. für jeden Ein anderer „Werttyp“, für den die CLR einen separaten Code generiert. Denn beim Instanziieren eines generischen Referenztyps ist die im Speicher zugewiesene Größe gleich, beim Instanziieren eines Werttyps ist die im Speicher zugewiesene Größe jedoch unterschiedlich.
Generische C#-Funktionen:
1 Wenn die Parameter des instanziierten generischen Typs identisch sind, verwendet der JIT-Editor den Typ wieder, sodass die dynamischen Generika von C# verwendet werden. Typfunktionen vermeiden das Problem der Codeaufblähung, das durch statische C++-Vorlagen verursacht werden kann.
2. Generische C#-Typen enthalten umfangreiche Metadaten, sodass die generischen C#-Typen auf leistungsstarke Reflexionstechnologie angewendet werden können.
3. Die Generika von C# verwenden die Einschränkungsmethode „Basisklasse, Schnittstelle, Konstruktor, Werttyp/Referenztyp“, um „explizite Einschränkungen“ für Typparameter zu implementieren, was nicht nur die Typsicherheit verbessert, sondern auch den Verlust von die hohe Flexibilität von C++-Vorlagen, die auf impliziten „Signatur“-Einschränkungen basieren
Generische C#-Vererbung:
C# Zusätzlich zur Möglichkeit, generische Typen separat zu deklarieren ( Zusätzlich zu Klassen und Strukturen) können Sie auch Deklarationen generischer Typen in Basisklassen einbinden. Wenn es sich bei der Basisklasse jedoch um eine generische Klasse handelt, wird ihr Typ entweder instanziiert oder von den von der Unterklasse deklarierten Typparametern abgeleitet (auch ein generischer Typ). 🎜>
Klasse D:C
Klasse E:C
Klasse F:C< ; string,int>
class G:C //Illegal
Der E-Typ stellt U und V für den C-Typ bereit, der von der oben genannten Unterklasse abgeleitet ist
Der F-Typ erbt von C
Der G-Typ ist nicht generisch und C Ist Generics, kann G keine generische Instanziierung für C bereitstellen
Mitglieder eines generischen Typs:
Mitglieder eines generischen Typs können Typparameter in der generischen Typdeklaration verwenden. Wenn der Typparameter jedoch keine Einschränkungen aufweist, können Sie für den Typ nur öffentliche Mitglieder verwenden, die von System.Object geerbt wurden. Wie unten gezeigt:
Generische Schnittstelle:
Die Typparameter der generischen Schnittstelle werden entweder instanziiert oder von den von der Implementierungsklasse deklarierten Typparametern abgeleitet
Generischer Delegat:
Generischer Delegat unterstützt die Anwendung von Parametertypen auf Delegaten-Rückgabewerte und -Parameter. Diese Parametertypen können auch mit rechtlichen Einschränkungen verbunden sein
Delegat bool MyDelegate
class MyClass
{
static bool F(int i){...}
static bool G(string s){...}
static void Main()
{
MyDelegate
MyDelegate
}
}
Generische Methode:
1. Der generische C#-Mechanismus unterstützt nur „Typparameter in der Methodendeklaration“ – also generische Methoden.
2. Der generische C#-Mechanismus unterstützt nicht die Einbeziehung von Typparametern in die Deklaration anderer Mitglieder (einschließlich Eigenschaften, Ereignisse, Indexer, Konstruktoren, Destruktoren), außer Methoden, aber diese Mitglieder selbst können in einem generischen Element enthalten sein Typ und verwenden Sie die Typparameter des generischen Typs.
3. Generische Methoden können sowohl in generischen als auch in nicht generischen Typen enthalten sein.
Generische Methodendeklaration: wie folgt
public static int FunctionName
Überladung generischer Methoden:
public void Function1
public void Function1(U a);
So geht es kann keine Überladung einer generischen Methode darstellen. Da der Compiler nicht feststellen kann, ob die generischen Typen T und U unterschiedlich sind, kann er nicht feststellen, ob die beiden Methoden unterschiedlich sind
public void Function1
public void Function1(int x);
Dies kann eine Überlastung darstellen
public void Function1
public void Function1
Dies kann keine Überladung einer generischen Methode darstellen. Da der Compiler nicht feststellen kann, ob A und B in den Einschränkungen unterschiedlich sind, kann er nicht feststellen, ob die beiden Methoden unterschiedlich sind.
Generisches Methodenumschreiben:
in Während des Umschreibens Im Prozess werden die Einschränkungen abstrakter Methoden in abstrakten Klassen standardmäßig geerbt. Wie folgt:
abstract class Base
{
public abstract T F
öffentliche Zusammenfassung T G
}
class MyClass:Base
{
öffentliche Überschreibung
}
Für die beiden überschriebenen Methoden in MyClass ist die
F-Methode zulässig und die Einschränkungen werden standardmäßig vererbt
G-Methode ist unzulässig, angegeben Alle Einschränkungen sind überflüssig
Generische Einschränkungen:
1 C#-Generika erfordern alle Einschränkungen für „Typparameter aller generischen Typen oder generischen Methoden“. Annahmen basieren auf „expliziten Einschränkungen“, um die von C# geforderte Typsicherheit aufrechtzuerhalten.
2. „Explizite Einschränkungen“ werden durch where-Klauseln ausgedrückt, und Sie können vier Arten von Einschränkungen angeben: „Basisklasseneinschränkungen“, „Schnittstelleneinschränkungen“, „Konstruktoreinschränkungen“ und „Werttyp/Referenztyp“. Einschränkungen“.
3. „Explizite Einschränkungen“ sind nicht erforderlich. Wenn „explizite Einschränkungen“ nicht angegeben sind, können generische Typparameter nur auf öffentliche Methoden im System.Object-Typ zugreifen. Beispiel: Im ersten Beispiel ist die obj-Mitgliedsvariable definiert. Beispielsweise fügen wir dem ersten Beispiel eine Test1-Klasse hinzu und definieren darin zwei öffentliche Methoden Func1 und Func2, wie unten gezeigt:
Unten Beginnen Sie mit der Analyse dieser Einschränkungen:
Basisklasseneinschränkungen:
Klasse A
{
public void Func1()
{ }
}
Klasse B
{
public void Func2()
{ }
}
Klasse C
wobei S : A
wobei T : B
{
öffentliches C(S s,T t)
{
//S's Variable kann die Func1-Methode aufrufen
s.Func1(); >
}
}
Schnittstellenbeschränkung:
Schnittstelle IA< ;T>
{
T Func1();
}
Schnittstelle IB
{
void Func2();
}
interface IC
{
class MyClass< T, V>
wobei T: IA
wobei V: IB, IC
{
public MyClass (T, v)
{
// T kann Func1 aufrufen
T.Func1 ();
// v Objekte können Func2 und Func3 aufrufen
v.Func2(); 🎜> Konstruktoreinschränkung:
Klasse A
🎜>
Klasse B
🎜>
Klasse C
{
T t;
public C()
{
t = new T();
}
}
Klasse D
{
public void Func()
Das Objekt erhält beim Kompilieren einen Fehler: Der Typ B muss über einen öffentlichen Konstruktor ohne Parameter verfügen, um ihn als Parameter „T“ im generischen Typ oder der generischen Methode C
Hinweis: C# unterstützt jetzt nur no- Einschränkungen des Parameterkonstruktors
Da wir zu diesem Zeitpunkt einen parametrisierten Konstruktor für Typ B geschrieben haben, verhindert dies, dass das System automatisch einen Parameterlosen Konstruktor für B erstellt. Wenn wir jedoch einen Parameterlosen Konstruktor zum B-Typ hinzufügen, Die Instanziierung von Objekt d meldet keinen Fehler. Der B-Typ ist wie folgt definiert:
Klasse B
{
public B()
{ }
public B(int i)
{ }
}
Werttyp/Referenztyp:
öffentliche Struktur A { }
öffentliche Klasse B { }
öffentliche Klasse C
C c2 = new C();
Das c2-Objekt hat beim Kompilieren einen Fehler erhalten: Der Typ „B“ muss ein nicht nullbarer Werttyp sein Verwenden Sie es als Parameter 'T' im generischen Typ oder Methor 'C
Zusammenfassung:
1 Die generischen Funktionen von C# werden von der CLR unterstützt Es unterscheidet sich von den statischen Vorlagen, die von C++ zur Kompilierungszeit unterstützt werden, und auch von den einfachen Generika, die von Java mithilfe der „Wischmethode“ auf Compilerebene unterstützt werden.
2. Die generische Unterstützung von C# umfasst vier generische Typen: Klassen, Strukturen, Schnittstellen, Delegaten und Methodenmitglieder.
3. Die Generika von C# verwenden die Einschränkungsmethode „Basisklasse, Schnittstelle, Konstruktor, Werttyp/Referenztyp“, um „explizite Einschränkungen“ für Typparameter zu implementieren. Es werden keine C++-Vorlagen unterstützt Einschränkungen.
Das Obige ist der Inhalt der generischen C#-Programmierung. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (m.sbmmt.com).