Question

Cette question a déjà une réponse ici :

je traversais Leçon Asp.Net MVC et j'ai appris que, pour qu'une méthode soit considérée comme une action pour un contrôleur,

  • Il ne doit pas avoir de "type générique ouvert"

Je comprends un peu les génériques et les utilise dans une certaine mesure, mais :

  • Qu'est-ce qu'un type générique ouvert dans .Net.
  • Existe-t-il une chose telle qu'un type générique fermé?
  • Type générique ouvert est un terme peu utilisé.Qu'est-ce qui est utilisé/confondu avec ?
Était-ce utile?

La solution

Le langage C# définit un type ouvert comme étant un type qui est soit un argument de type, soit un type générique défini avec des arguments de type inconnus :

Tous les types peuvent être classés en types ouverts ou en types fermés.Un Type ouvert est un type qui implique des paramètres de type.Plus précisement:

  • Un paramètre de type définit un type ouvert.
  • Un type tableau est un type ouvert si et seulement si son type d’élément est un type ouvert.
  • UN type construit est un type ouvert si et seulement si un ou plusieurs de ses arguments de type sont un Type ouvert.UN type imbriqué construit est un type ouvert si et seulement si un ou plusieurs de ses arguments de type ou les arguments de type de son ou ses types contenants sont un type ouvert.

UN type fermé est un type qui n’est pas un type ouvert.

Donc T, List<T>, et Dictionary<string,T>, et Dictionary<T,U> sont tous des types ouverts (T et U sont des arguments de type) alors que List<int> et Dictionary<string,int> sont des types fermés.

Il existe un concept connexe :Un type générique non lié est un type générique avec des arguments de type non spécifiés.Un type non lié ne peut pas être utilisé dans des expressions autres que typeof() et vous ne pouvez pas l'instancier ou appeler ses méthodes.Par exemple, List<> et Dictionary<,> sont des types non liés.

Pour clarifier la distinction subtile entre un type ouvert et un type non lié :

class Program {
   static void Main() { Test<int>(); }
   static void Test<T>() {
      Console.WriteLine(typeof(List<T>)); // Print out the type name
   }
}

Si vous exécutez cet extrait, il s'imprimera

System.Collections.Generic.List`1[System.Int32]

qui est le nom CLR de List<int>.Il est clair au moment de l'exécution que l'argument type est System.Int32.Cela fait List<T> un lié Type ouvert.

Au moment de l'exécution, vous pouvez utiliser la réflexion pour lier des arguments de type à des paramètres de type non spécifiés de types génériques non liés avec le Type.MakeGenericType méthode:

Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
     Console.WriteLine("Constructed a List<int> type.");

Vous pouvez vérifier si un type est un type générique non lié (définition de type générique) à partir duquel vous pouvez construire des types liés avec le Type.IsGenericTypeDefinition propriété:

Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False

Pour obtenir le type indépendant d'un type construit au moment de l'exécution, vous pouvez utiliser le Type.GetGenericTypeDefinition méthode.

Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)

Notez que pour un type générique, vous pouvez avoir soit une définition de type totalement indépendante, soit une définition complètement liée.Vous ne pouvez pas lier certains paramètres de type et laisser d’autres non liés.Par exemple, vous ne pouvez pas avoir Dictionary<int,> ou Dictionary<,string>.

Autres conseils

Il suffit d'ajouter:

Dictionary<string, T> (ou plus précisément Dictionary<string,>) est encore un type ouvert.

Exemple:

void Foo<T>(Dictionary<string,T> dic) { ... }

Un « type générique ouvert » est juste un type générique qui ne dispose pas encore de son type spécifié (par exemple, CargoCrate<T>). Il devient une fois un type concret "fermé" a été attribué (par exemple CargoCrate<Widget>).

Par exemple, supposons que vous avez quelque chose comme ceci:

public class Basket<T> {
  T[] basketItems;
}

public class PicnicBlanket<T> {
  Basket<T> picnicBasket;   // Open type here. We don't know what T is.
}

                                 // Closed type here: T is Food.
public class ParkPicnicBlanket : PicnicBlanket<Food> {
}

Ici, le type de picnicBasket est ouvert: rien n'a encore été affecté à T. Lorsque vous faites un PicnicBlanket en béton avec un type spécifique - par exemple, en écrivant PicnicBlanket<Food> p = new PicnicBlanket<Food>() - nous l'appelons maintenant fermé

.

Il existe trois types de types génériques. Pour faire court, dans ce (simplifié) déclaration:

public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  • Dictionary<TKey, TValue> est un type générique unbounded .

  • KeyValuePair<TKey, TValue> est, dans ce cas, un type générique ouvert construit . Il a quelques paramètres de type, mais ils sont déjà définis ailleurs (dans le dictionnaire, dans ce cas).

  • Dictionary<string, int> serait fermé construit type générique .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top