Comme ce chapitre est très long, il faudra peut-être le diviser en plusieurs parties :)
20. Génériques
20.1 Déclaration de classe générique
Une déclaration de classe générique est une déclaration d'une classe qui nécessite des paramètres de type pour former le type réel.
Une déclaration de classe peut éventuellement définir des paramètres de type.
déclaration de classe : (déclaration de classe)
attributesopt class-modifiersopt identifiant de classeopt type-parameter-listopt class –baseopt type-parameter-constraints-clauseopt class-body;opt (attribut facultatif modificateur de classe classe facultative identifier Liste de paramètres de type facultative Classe de base facultative Déclaration de contrainte de paramètre de type facultative Corps de classe facultative ; Facultatif)
À moins qu'une liste de paramètres de type ne soit fournie, une déclaration de classe n'a pas besoin de fournir une instruction de contrainte paramétrée par type.
Une déclaration de classe qui fournit une liste de paramètres de type est une déclaration de classe générique. De plus, toute classe incorporée dans une déclaration de classe générique ou une déclaration de structure générique est elle-même une déclaration de classe générique car les paramètres de type du type conteneur doivent être fournis pour créer un type construit
Les classes de type générique sont référencées à l'aide de construit ; types (§20.5). Étant donné la déclaration de classe générique
class List
Voici quelques exemples de types construits, List>. Un type construit peut prendre un ou plusieurs paramètres, par exemple List
Les types génériques ne peuvent pas être « surchargés » ; c'est-à-dire que, comme les types ordinaires, ils doivent être nommés de manière unique dans une portée.
classe C{}
classe C
classe C{}//Erreur, C est défini
deux fois. Cependant, les règles de recherche de type utilisées dans la recherche de nom de type non qualifié (§20.9.3) et l'accès aux membres (§20.9.4) prennent en compte le nombre de paramètres de type.
20.1.1 Paramètres de type
Les paramètres de type peuvent être fournis sur une déclaration de classe. Chaque paramètre de type est un simple identifiant qui indique un espace réservé pour les paramètres de type utilisés pour créer un type construit. Les paramètres de type sont des espaces réservés formels pour les types qui seront fournis ultérieurement. En revanche, les paramètres de type §20.5.1) sont simplement un proxy du type réel lorsque le type construit est référencé.
liste des paramètres de type : (Liste des paramètres de type :)
paramètre de type (paramètre de type)
paramètres de type paramètre de type (paramètre de type, paramètre de type)
paramètre de type : (paramètre de type :)
identifiant d'attributsopt (identifiant facultatif d'attribut)
Chaque paramètre de type dans une déclaration de classe définit un nom dans l'espace de déclaration de la classe (§3.3). Par conséquent, il ne peut pas avoir le même nom qu’un autre paramètre de type ou membre déclaré dans la classe. Un paramètre de type ne peut pas avoir le même nom que le type lui-même.
La portée des paramètres de type dans une classe (§3.7), y compris la classe de base, l'instruction de contrainte de paramètre de type et le corps de la classe. Contrairement aux membres d’une classe, cela ne s’étend pas aux classes dérivées. Dans sa portée, un paramètre de type peut être utilisé comme type.
type :
value-type (type de valeur)
reference-type (type de référence)
type-parameter (type paramètre)
en raison du paramètre de type Peut être instancié par de nombreux arguments de type réels différents, qui auront des opérations et des restrictions légèrement différentes de celles des autres types. Comprend les éléments suivants.
Les paramètres de type ne peuvent pas être utilisés pour déclarer directement un type de base ou une interface.
Pour les règles de recherche de membres sur les paramètres de type, si des contraintes existent, elles dépendent des contraintes appliquées au paramètre de type. Voir §20.7.4 pour une description plus détaillée.
Les conversions possibles pour un paramètre de type dépendent des contraintes (le cas échéant) appliquées au paramètre de type. Voir §20.7.4 pour plus de détails.
Le null littéral ne peut pas être converti en type donné par le paramètre type, sauf si le paramètre type est contraint par une contrainte de classe (§20.7.4). Cependant, une expression de valeur par défaut (§20.8.1) peut être utilisée à la place. De plus, les valeurs d'un type donné par un paramètre de type peuvent être comparées à null en utilisant "==" et "!=" (§20.8.4).
Si les paramètres de type sont contraints par une contrainte de constructeur (§20.7), la nouvelle expression ne peut être utilisée qu'avec un seul paramètre de type.
Les paramètres de type ne peuvent être utilisés nulle part dans les attributs.
Les paramètres de type ne peuvent pas être utilisés pour l'accès aux membres, ni représenter le nom de type d'un membre statique ou d'un type imbriqué (§20.9.1, §20.9.4).
Dans le code non sécurisé, les paramètres de type ne peuvent pas être utilisés comme types gérés (§18.2).
En tant que type, un paramètre de type est purement une construction au moment de la compilation. Au moment de l'exécution, chaque paramètre de type est lié au type d'exécution, qui est spécifié par les arguments de type fournis par la déclaration de type générique. Pour cette raison, à l'exécution, le type d'une variable déclarée avec un paramètre type est un type fermé (§20.5.2). Toutes les instructions et expressions exécutées au moment de l'exécution utilisent des paramètres de type du type réel fourni par ce paramètre comme argument de type.
20.1.2 Type d'instance
Chaque déclaration de classe est associée à un type construit, c'est-à-dire un type d'instance. Pour une déclaration de classe générique, le type d'instance est formé en créant un type construit (§20.4) à partir de la déclaration de type, qui utilise chaque argument de type correspondant au paramètre de type. Étant donné qu'un type instancié utilise des paramètres de type, il n'est valide que dans la portée du paramètre de type (dans la déclaration de classe). Le type d'instance est le type de this dans la déclaration de classe. Pour les classes non génériques, le type d'instance est simplement un type déclaré. Vous trouverez ci-dessous plusieurs classes déclarées, ainsi que leurs types d'instances.
class A<T> //实例类型:A<T> { class B{} //实例类型:A<T>.B class C<U>{} //实例类型:A<T>.C<U> } class D{} //实例类型:D
La classe de base spécifiée dans la déclaration de classe peut être un type construit (§20.5). Une classe de base elle-même ne peut pas être un paramètre de type, mais elle peut contenir des paramètres de type dans sa portée.
class Extend
La déclaration de classe générique ne peut pas utiliser System.Attribute comme classe de base directe ou indirecte.
Une interface de base spécifiée dans une déclaration de classe peut être un type d'interface construit (§20.5). L'interface de base elle-même ne peut pas être un paramètre de type, mais elle peut contenir des paramètres de type dans sa portée. Le code suivant montre comment implémenter et étendre le type construit.
class C<U,V>{} Interface I1<V>{} class D:C<string , int>,I1<string>{} class E<T>:C<int,T> ,I1<T>{}
Les méthodes d'une classe qui remplacent ou implémentent des méthodes à partir d'une classe ou d'une interface de base doivent fournir des méthodes appropriées pour le type spécifique. Le code ci-dessous montre comment la méthode peut être remplacée et implémentée. Ceci est expliqué plus en détail au §20.1.10.
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] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如List
以上就是C#2.0 Specification(泛型一)的内容,更多相关内容请关注PHP中文网(www.php.cn)!