Heim  >  Artikel  >  Backend-Entwicklung  >  C#2.0-Spezifikation (Generika 1)

C#2.0-Spezifikation (Generika 1)

黄舟
黄舟Original
2017-01-03 10:22:211149Durchsuche

Da dieses Kapitel sehr lang ist, muss es möglicherweise in mehrere Teile unterteilt werden:)

20. Generics

20.1 Generische Klassendeklaration

Eine generische Klassendeklaration ist eine Deklaration einer Klasse, die Typparameter benötigt, um den tatsächlichen Typ zu bilden.



Eine Klassendeklaration kann optional Typparameter definieren.

class-declaration: (class-declaration)
attributesopt class-modifikatorsopt klassenbezeichneropt type-parameter-listopt class –baseopt type-parameter-constraints-clauseopt class-body;opt (attribute optional class modifier Optionale Klasse Bezeichner Optionale Typparameterliste Optionale Basisklasse Optionale Typparameter-Einschränkungsanweisung Optionaler Klassenkörper; Optional)
Sofern keine Typparameterliste bereitgestellt wird, muss eine Klassendeklaration keine typparametrisierte Einschränkungsanweisung bereitstellen.

Eine Klassendeklaration, die eine Typparameterliste bereitstellt, ist eine generische Klassendeklaration. Darüber hinaus ist jede in eine generische Klassendeklaration oder generische Strukturdeklaration eingebettete Klasse selbst eine generische Klassendeklaration, da Typparameter des enthaltenden Typs bereitgestellt werden müssen, um einen konstruierten Typ zu erstellen.

Generische Typklassen werden mithilfe von „Konstruktiv“ referenziert Typen (§20.5). Angesichts der generischen Klassendeklaration

class List8742468051c85b06f0a0af9e3e506b5c{}
Hier sind einige Beispiele für konstruierte Typen, List8742468051c85b06f0a0af9e3e506b5c, Listbd43222e33876353aff11e13a7dc75f6 und List74c6f25e79e205a53afa93c32870c098>. Ein konstruierter Typ kann einen oder mehrere Parameter annehmen. List8742468051c85b06f0a0af9e3e506b5c wird beispielsweise als offener konstruierter Typ bezeichnet. Ein konstruierter Typ, der keine Typparameter wie Listbd43222e33876353aff11e13a7dc75f6 verwendet, wird als geschlossener konstruierter Typ bezeichnet.

Generische Typen können nicht „überladen“ werden; das heißt, sie müssen wie gewöhnliche Typen innerhalb eines Bereichs eindeutig benannt werden.


Klasse C{}
Klasse Cd94943c0b4933ad8cac500132f64757f{}//Fehler, C ist zweimal definiert
Klasse Cf3887e50b478d7d3734323cd28ecc8ff{}//Fehler, C ist definiert
zweimal. Die Typsuchregeln, die bei der Suche nach unqualifizierten Typnamen (§20.9.3) und beim Memberzugriff (§20.9.4) verwendet werden, berücksichtigen jedoch die Anzahl der Typparameter.

20.1.1 Typparameter

Typparameter können in einer Klassendeklaration bereitgestellt werden. Jeder Typparameter ist ein einfacher Bezeichner, der einen Platzhalter für die Typparameter angibt, die zum Erstellen eines konstruierten Typs verwendet werden. Typparameter sind formale Platzhalter für Typen, die später bereitgestellt werden. Im Gegensatz dazu sind Typparameter (§20.5.1) lediglich ein Proxy für den tatsächlichen Typ, wenn auf den konstruierten Typ verwiesen wird.

Typparameterliste: (Typparameterliste:)
3fdd6d87c334c98c026327cd9a403bcc Typparameter (Typparameter)
Typparameter Typparameter (Typparameter, Typparameter)
Typparameter: (Typparameter:)
Attributeopt-Bezeichner (optionaler Attributbezeichner) ​​

Jeder Typparameter in einer Klassendeklaration definiert einen Namen im Deklarationsraum der Klasse (§3.3). Daher darf er nicht denselben Namen wie ein anderer in der Klasse deklarierter Typparameter oder Member haben. Ein Typparameter darf nicht denselben Namen haben wie der Typ selbst.

Der Umfang der Typparameter in einer Klasse (§3.7), einschließlich Basisklasse, Typparameter-Einschränkungsanweisung und Klassenkörper. Im Gegensatz zu Mitgliedern einer Klasse erstreckt es sich nicht auf abgeleitete Klassen. Innerhalb seines Gültigkeitsbereichs kann ein Typparameter als Typ verwendet werden.

Typ:

Werttyp (Werttyp)
Referenztyp (Referenztyp)
Typparameter (Typparameter)
aufgrund des Typparameters Kann sein wird durch viele verschiedene tatsächliche Typargumente instanziiert, die leicht andere Operationen und Einschränkungen haben als andere Typen. Enthält Folgendes.

Typparameter können nicht zum direkten Deklarieren eines Basistyps oder einer Basisschnittstelle verwendet werden.
Wenn Einschränkungen für Elementsuchregeln für Typparameter vorhanden sind, hängen diese von den Einschränkungen ab, die auf den Typparameter angewendet werden. Eine ausführlichere Beschreibung finden Sie in §20.7.4.



Mögliche Konvertierungen für einen Typparameter hängen von den Einschränkungen (falls vorhanden) ab, die auf den Typparameter angewendet werden. Einzelheiten finden Sie in §20.7.4.
Literal null kann nicht in den durch den Typparameter angegebenen Typ konvertiert werden, es sei denn, der Typparameter ist durch eine Klassenbeschränkung eingeschränkt (§20.7.4). Stattdessen kann jedoch ein Standardwertausdruck (§20.8.1) verwendet werden. Darüber hinaus können Werte eines Typs, der durch einen Typparameter angegeben wird, mithilfe von „==" und „!=" mit Null verglichen werden (§20.8.4).
Wenn die Typparameter durch eine Konstruktor-Einschränkung (§20.7) eingeschränkt sind, kann der neue Ausdruck nur mit einem Typparameter verwendet werden.
Typparameter können nirgendwo innerhalb von Attributen verwendet werden.
Typparameter können nicht für den Memberzugriff verwendet werden oder den Typnamen eines statischen Members oder eines verschachtelten Typs darstellen (§20.9.1, §20.9.4).
In unsicherem Code können Typparameter nicht als verwaltete Typen verwendet werden (§18.2).

Als Typ ist ein Typparameter ein reines Konstrukt zur Kompilierungszeit. Zur Laufzeit ist jeder Typparameter an den Laufzeittyp gebunden, der durch die von der generischen Typdeklaration bereitgestellten Typargumente angegeben wird. Aus diesem Grund ist der Typ einer mit einem Typparameter deklarierten Variablen zur Laufzeit ein geschlossener Typ (§20.5.2). Alle zur Laufzeit ausgeführten Anweisungen und Ausdrücke verwenden Typparameter des tatsächlichen Typs, der von diesem Parameter als Typargument bereitgestellt wird.



20.1.2 Instanztyp

Jeder Klassendeklaration ist ein konstruierter Typ zugeordnet, d. h. ein Instanztyp. Bei einer generischen Klassendeklaration wird der Instanztyp gebildet, indem aus der Typdeklaration ein konstruierter Typ (§20.4) erstellt wird, der jedes dem Typparameter entsprechende Typargument verwendet. Da ein instanziierter Typ Typparameter verwendet, ist er nur innerhalb des Typparameterbereichs (innerhalb der Klassendeklaration) gültig. Der Instanztyp ist der Typ davon in der Klassendeklaration. Bei nicht generischen Klassen ist der Instanztyp nur ein deklarierter Typ. Unten sind mehrere deklarierte Klassen zusammen mit ihren Instanztypen aufgeführt.


20.1.3 Basisklassenspezifikation
class A<T> //实例类型:A<T>
{
class B{} //实例类型:A<T>.B
class C<U>{} //实例类型:A<T>.C<U>
}
class D{} //实例类型:D

Die in der Klassendeklaration angegebene Basisklasse kann ein konstruierter Typ sein (§20.5). Eine Basisklasse selbst kann kein Typparameter sein, sie kann jedoch Typparameter in ihrem Gültigkeitsbereich enthalten.


class Extendd94943c0b4933ad8cac500132f64757f: V{}//Fehler, Typparameter wird als Basisklasse verwendet
Generische Klassendeklaration kann System.Attribute nicht als direkte oder indirekte Basisklasse verwenden.

Eine in einer Klassendeklaration angegebene Basisschnittstelle kann ein konstruierter Schnittstellentyp sein (§20.5). Die Basisschnittstelle selbst kann kein Typparameter sein, sie kann jedoch Typparameter in ihrem Gültigkeitsbereich enthalten. Der folgende Code zeigt, wie der konstruierte Typ implementiert und erweitert wird.



Die von einem generischen Typ deklarierte Basisschnittstelle muss die in §20.3.1 beschriebenen Eindeutigkeitsregeln erfüllen.
class C<U,V>{}
Interface I1<V>{}
class D:C<string , int>,I1<string>{}
class E<T>:C<int,T> ,I1<T>{}

Methoden einer Klasse, die Methoden einer Basisklasse oder Schnittstelle überschreiben oder implementieren, müssen geeignete Methoden für den spezifischen Typ bereitstellen. Der folgende Code zeigt, wie die Methode überschrieben und implementiert werden kann. Dies wird in §20.1.10 näher erläutert.



20.1.4 Mitglieder generischer Klassen
class C<U,V>
{
public virtual void M1(U x , List<V> y){…}
}
interface I1<V>
{
V M2(V x);
}
class D:C<string , int>,I1<string>
{
public override void M1(string x , List<int> y){…}
public string M2(string x){…}
}

泛型类的所有成员都可以直接地或者作为构造类型的一部分,从任何封闭类(enclosing class)中使用类型参数。当特定的封闭构造类型在运行时被使用时,类型参数的每次使用都由构造类型所提供的实际类型实参所代替。例如


class C<V>
{ 
public V f1; 
public C<V> f2=null;
public C(V x){
this.f1 = x;
this.f2 = this;
}
}
class Application
{
static void Main(){
C<int> x1= new C<int >(1);
Console.WriteLine(x1.f1); //打印1
C<double> x2 = new C<double>(3.1415);
Console.WriteLine(x2.f1); //打印 3.1415
}
}

在实例函数成员之内,this的类型就是声明的实例类型(§20.1.2)。

除了使用类型参数作为类型和成员,在泛型类声明中也遵循和非泛型类成员相同的规则。适用于特定种类成员的附加规则将在后面几节进行讨论。

20.1.5泛型类中的静态字段

在一个泛型类声明中的静态变量,在相同封闭构造类型(§20.5.2)所有实例中被共享,但在不同封闭构造类型的实例中[1],是不被共享的。这些规则不管静态变量的类型包含那种类型参数都适用。

例如

class C<V>
{
static int count = 0;
public C()
{
count++;
}
public static int Count{
get{return count;}
}
}
class Application
{
static void Main()
{
C<int> x1 = new C<int>();
Console.WriteLine(C<int>.Count);//打印 1
C<double> x2 = new C<double>();
Console.WriteLine(C<int>.Count);//打印 1
C<int> x3 = new C<int>();
Console.WriteLine(C<int>.Count);//打印 2
}
}

[1] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如Listbd43222e33876353aff11e13a7dc75f6 和List98c455a79ddfebb79781bff588e7b37e 这二者的实例是不能共享静态变量的。

以上就是C#2.0 Specification(泛型一)的内容,更多相关内容请关注PHP中文网(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
Vorheriger Artikel:C# 2.0-Spezifikation (四)Nächster Artikel:C# 2.0-Spezifikation (四)