2008-09-30 9 views
6

J'ai appris sur les bases de C#, mais ne l'ai pas rencontré une bonne explication de ce que cela est:Quelle est la « < > » syntaxe au sein de C#

var l = new List<string>(); 

Je ne sais pas ce que le <string> fait ou si c'est le List qui fait la magie. J'ai également vu des objets lancés dans les tags < >. Est-ce que quelqu'un peut m'expliquer cela avec des exemples, s'il vous plaît?

Répondre

24

C'est la syntaxe générique pour C#.

Le concept de base est qu'il vous permet d'utiliser un espace réservé de type et de remplacer le type réel réel au moment de la compilation.

Par exemple, l'ancienne:

ArrayList foos = new Arraylist(); 
foos.Add("Test"); 

travaillé en faisant magasin ArrayList une liste de System.Objects (Le type de base pour toutes les choses .NET).

Ainsi, lors de l'ajout ou la récupération d'un objet à partir de la liste, le CLR devrait jeter à l'objet, au fond ce qui se passe vraiment est la suivante:

foos.Add("Test" as System.Object); 
string s = foos[1] as String. 

Cela provoque une pénalité de performance de la coulée, et Il est aussi dangereux parce que je peux le faire:

ArrayList listOfStrings = new ArrayList(); 
listOfStrings.Add(1); 
listOfStrings.Add("Test"); 

cela va compiler très bien, même si je mets un entier listOfStrings.

Generics a changé tout cela, maintenant je peux en utilisant Generics déclarer quel type ma collection attend:

List<int> listOfIntegers = new List<int>(); 
List<String> listOfStrings = new List<String>(); 

listOfIntegers.add(1); 

// Compile time error. 
listOfIntegers.add("test"); 

Cela fournit le type de compilation sécurité, ainsi que des opérations coûteuses évite de coulée.

La façon dont vous en tirer parti est assez simple, bien qu'il existe des cas de bords avancés. Le concept de base est de rendre votre type de classe agnostique en utilisant un espace réservé de type, par exemple, si je voulais créer une classe générique "Ajouter deux choses".

public class Adder<T> 
{ 
    public T AddTwoThings(T t1, T t2) 
    { 
     return t1 + t2; 
    } 
} 

Adder<String> stringAdder = new Adder<String>(); 
Console.Writeline(stringAdder.AddTwoThings("Test,"123")); 

Adder<int> intAdder = new Adder<int>(); 
Console.Writeline(intAdder.AddTwoThings(2,2)); 

Pour une explication beaucoup plus détaillée des génériques, je ne peux pas recommander suffisamment le livre CLR via C#.

+0

fyi la pénalité de performance lors de l'utilisation de ArrayLists est lorsque les types de valeur boxe et unboxing se produit (structs, ints, flotteurs, etc). Il n'y a pas de pénalité de performance appréciable pour renvoyer la référence d'objet à une référence de chaîne. –

+1

De plus, c'est un point mineur, mais les génériques (ou les types construits) dans .net ne sont pas réalisés (construits) avant l'exécution. Le compilateur vérifie seulement votre code au moment de la compilation et s'assure que pour IList .Add (T) que var dans 'Add (var)' est implicitement convertible en T. –

+2

L'exemple AddTwoThings a été couvert plusieurs fois sur SO, et n'est pas valide. – erikkallen

1

Voici les génériques .NET. Le type dans le <> indique le type d'élément contenu dans la liste.

avec ArrayList vous auriez à jeter les éléments à l'intérieur ...

int x = (int)myArrayList[4]; 

avec liste, vous pouvez éviter cette étape parce que le compilateur connaît déjà le type.

int x = myList[4]; 

Les génériques sont disponibles dans .NET 2.0 et versions ultérieures.

1

Ce sont des génériques. Vous créez une liste qui contient uniquement des chaînes. Vous pouvez également dire

List<int> 

et d'obtenir une liste qui ne contient que des ints. Les génériques sont un sujet énorme, trop gros pour une seule réponse ici.

+0

Merci pour cela et j'ai édité la question –

+0

NP. J'ai également supprimé ma suggestion. Dans le trou de la mémoire, ils vont. –

5

Il est génériques - c'est une forme de type paramétrisation. Dans votre exemple, cela fait référence à une liste de chaînes - la liste ne contiendra jamais de chaînes: le compilateur la traite (à peu près) comme si partout où les docs de l'API mentionnent "T", elle dit réellement "string". Donc, vous ne pouvez y ajouter que des chaînes, et si vous utilisez l'indexeur, vous n'avez pas besoin de convertir en chaîne, etc.

Pour être honnête, donner une couverture détaillée des génériques sur un forum en ligne est pratiquement impossible. (En C# en profondeur, je prends près de 50 pages sur les génériques.) Cependant, armé du nom de la fonctionnalité, vous devriez être dans une bien meilleure position pour en savoir plus. Le MSDN "Introduction to C# Generics" est probablement un bon point de départ. Poser des questions spécifiques sur les génériques sur le SO est susceptible de donner de bons résultats - Je ne pense pas que cela puisse vraiment être couvert correctement dans une question/réponse.

+0

Merci, une bonne réponse. –

1

Ce sont des génériques en action. Une liste régulière stocke les éléments de type Object. Cela nécessite de couler entre les types. Cela vous permettra également de stocker n'importe quel type d'élément dans une instance d'une liste. Lorsque vous parcourez des éléments de cette liste, vous ne pouvez pas être sûr qu'ils sont tous d'un certain type (du moins pas sans lancer chaque élément). Par exemple permet de dire que vous créez une liste comme ceci:

List listOfStrings = new List(); 

Rien n'empêche quelqu'un de faire quelque chose comme ceci:

listOfStrings.add(6); //Not a string 

Une liste générique vous permettra de spécifier une liste fortement typée.

List<string> listOfStrings = new List<string>(); 
listOfStrings.add("my name"); //OK 
listofStrings.add(6); //Throws a compiler error 

Il y a un des exemples plus complets ici Generics

0

<> est pour les médicaments génériques. Dans votre exemple spécifique, cela signifie que la liste est une liste de chaînes, pas une liste d'ints.

Les génériques sont utilisés pour permettre à un type d'être, bien, générique. Il est utilisé ALOT dans les collections pour leur permettre de prendre différents types afin qu'ils puissent fonctionner comme un tableau normal et toujours attraper les types invalides affectés à la compilation. Fondamentalement, cela permet à une classe de dire: «Je dois être associé à un type T spécifique, mais je ne veux pas coder exactement ce type et laisser l'utilisateur le sélectionner».Un simple tableau, par exemple, pourrait ressembler à:

public class MyArray<T> { 
    private T[] _list; 

    public MyArray() : this.MyArray(10); 
    public MyArray(int capacity) 
    { _list = new T[capacity]; } 

    T this[int index] { 
     get { return _list[index]; } 
     set { _list[index] = value; } 
    } 
} 

Ici, nous avons une liste privée de type T qui est accessible en utilisant notre classe comme un tableau normal. Peu importe le type, peu importe notre code. Mais n'importe qui utilisant la classe pourrait l'utiliser comme, disons MyArray<string> pour créer une liste de chaînes, alors que quelqu'un d'autre pourrait l'utiliser comme MyArray<bool> et créer une liste de drapeaux.

Questions connexes