Heim  >  Artikel  >  Backend-Entwicklung  >  Generische C#-Programmierung

Generische C#-Programmierung

黄舟
黄舟Original
2016-12-21 14:47:351051Durchsuche

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 test = new Test(obj);

Console.WriteLine("int:" + test.obj);

string obj2 = "hello world";

Test test1 = new Test(obj2);

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::.ctor(!0)

IL_0009: stloc.1

IL_000a: " ldstr "int:"

IL_000f: ldloc.1

IL_0010: ldfld !0 class CSharpStudy1.Test`1::obj

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::.ctor(!0)

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-Typ – er instanziiert den generischen Typ nicht und T fungiert nur als Platzhalter in der Mitte. Beispiel:

wird in den Testtyp-Metadaten 2 angezeigt. Wenn der JIT-Compiler während der JIT-Kompilierung zum ersten Mal auf Test trifft, ersetzt er die „generische Version“ durch int T in IL-Code und Metadaten – Instanziierung generischer Typen. Beispiel:

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. Ich persönlich denke, dass er als F-Erbung einer nicht generischen Klasse angesehen werden kann.

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(T-Wert);

class MyClass

{

static bool F(int i){...}

static bool G(string s){...}

static void Main()

{

MyDelegate

MyDelegate p1 = new MyDelegate(F);

}

}



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(T value){...}



Überladung generischer Methoden:

public void Function1(T a);

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(int x);

public void Function1(int x);

Dies kann eine Überlastung darstellen



public void Function1(T t) where T:A;

public void Function1(T t) where T:B;

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(T t,U u) wobei U:T;

öffentliche Zusammenfassung T G(T t) wobei T:IComparable;

}



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 wobei T : new()

{

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 verwenden zu können.

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 (www.php.cn).



Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn