2010-11-15 6 views
29

J'ai besoin d'un moyen pour obtenir le nom d'un type, quand type.IsGenericType = true.C# Obtenir le nom de type générique

Type t = typeof(List<String>); 
    MessageBox.Show(..?..); 

Ce que je veux, est une boîte de message à la pop avec List montrant ... Comment puis-je faire?

Répondre

29
Type t = ...; 

if (t.IsGenericType) 
{ 
    Type g = t.GetGenericTypeDefinition(); 

    MessageBox.Show(g.Name);        // displays "List`1" 

    MessageBox.Show(g.Name.Remove(g.Name.IndexOf('`'))); // displays "List" 
} 
+4

Si vous avez besoin du type T d'un type générique comme '' liste vous pouvez utiliser quelque chose comme ceci 't.GetGenericArguments() [0] .Name'. J'en avais besoin il y a un moment et je ne l'ai trouvé nulle part. Cela retournera 'string' dans le cas où vous avez' List ' –

38

Vous pouvez mettre en œuvre une méthode d'extension pour obtenir le « amical nom "d'un type, comme ceci:

public static class TypeNameExtensions 
{ 
    public static string GetFriendlyName(this Type type) 
    { 
     string friendlyName = type.Name; 
     if (type.IsGenericType) 
     { 
      int iBacktick = friendlyName.IndexOf('`'); 
      if (iBacktick > 0) 
      { 
       friendlyName = friendlyName.Remove(iBacktick); 
      } 
      friendlyName += "<"; 
      Type[] typeParameters = type.GetGenericArguments(); 
      for (int i = 0; i < typeParameters.Length; ++i) 
      { 
       string typeParamName = typeParameters[i].Name; 
       friendlyName += (i == 0 ? typeParamName : "," + typeParamName); 
      } 
      friendlyName += ">"; 
     } 

     return friendlyName; 
    } 
} 

Avec dans votre projet, vous pouvez maintenant dire:

MessageBox.Show(t.GetFriendlyName()); 

Et il affiche « Liste < chaîne > ».

Je sais que l'OP n'a pas demandé les paramètres de type générique, mais je le préfère de cette façon. ;-)

Espaces de noms et standard aliases for built-in types laissés en exercice pour le lecteur.

+2

Avec une nouvelle beauté C#, vous pouvez maintenant écrire tout le bit après la vérification backtick dans une ligne (quoique longue), et cela va aussi traiter des génériques imbriqués: 'friendlyName + = $" <{string.Join (",", type.GetGenericArguments(). Sélectionnez (p => type.GetFriendlyName()))}> "' – joshcomley

3

J'ai amélioré la version de yoyos pour l'utilisation dans la génération de code. Notez que tous les types sont maintenant référencés full qualifié => global :: System.String.

  public static string GetFriendlyTypeName(Type type) 
      { 
       string friendlyName = type.Name; 
       if (type.IsGenericType) 
       { 
        int iBacktick = friendlyName.IndexOf('`'); 
        if (iBacktick > 0) 
        { 
         friendlyName = friendlyName.Remove(iBacktick); 
        } 
        friendlyName += "<"; 
        Type[] typeParameters = type.GetGenericArguments(); 
        for (int i = 0; i < typeParameters.Length; ++i) 
        { 
         string typeParamName = GetFriendlyTypeName(typeParameters[i]); 
         friendlyName += (i == 0 ? typeParamName : "," + typeParamName); 
        } 
        friendlyName += ">"; 
        friendlyName = "global::" + type.Namespace + "." + friendlyName; 
       } 
       else 
       { 
        friendlyName = "global::" + type.FullName; 
       } 

       return friendlyName.Replace('+', '.'); 
      } 
5
public static class TypeNameExtensions 
{ 
    public static string GetFriendlyName(this Type type) 
    { 
     var friendlyName = type.Name; 
     if (!type.IsGenericType) return friendlyName; 

     var iBacktick = friendlyName.IndexOf('`'); 
     if (iBacktick > 0) friendlyName = friendlyName.Remove(iBacktick); 

     var genericParameters = type.GetGenericArguments().Select(x => x.GetFriendlyName()); 
     friendlyName += "<" + string.Join(", ", genericParameters) + ">"; 

     return friendlyName; 
    } 
} 
14

Mon point de vue sur l'approche de Yoyo. Assure des noms plus conviviaux pour les primitives, gère les tableaux et est récursif pour gérer les génériques imbriqués. Également des tests unitaires.

private static readonly Dictionary<Type, string> _typeToFriendlyName = new Dictionary<Type, string> 
    { 
     { typeof(string), "string" }, 
     { typeof(object), "object" }, 
     { typeof(bool), "bool" }, 
     { typeof(byte), "byte" }, 
     { typeof(char), "char" }, 
     { typeof(decimal), "decimal" }, 
     { typeof(double), "double" }, 
     { typeof(short), "short" }, 
     { typeof(int), "int" }, 
     { typeof(long), "long" }, 
     { typeof(sbyte), "sbyte" }, 
     { typeof(float), "float" }, 
     { typeof(ushort), "ushort" }, 
     { typeof(uint), "uint" }, 
     { typeof(ulong), "ulong" }, 
     { typeof(void), "void" } 
    }; 

    public static string GetFriendlyName(this Type type) 
    { 
     string friendlyName; 
     if (_typeToFriendlyName.TryGetValue(type, out friendlyName)) 
     { 
      return friendlyName; 
     } 

     friendlyName = type.Name; 
     if (type.IsGenericType) 
     { 
      int backtick = friendlyName.IndexOf('`'); 
      if (backtick > 0) 
      { 
       friendlyName = friendlyName.Remove(backtick); 
      } 
      friendlyName += "<"; 
      Type[] typeParameters = type.GetGenericArguments(); 
      for (int i = 0; i < typeParameters.Length; i++) 
      { 
       string typeParamName = typeParameters[i].GetFriendlyName(); 
       friendlyName += (i == 0 ? typeParamName : ", " + typeParamName); 
      } 
      friendlyName += ">"; 
     } 

     if (type.IsArray) 
     { 
      return type.GetElementType().GetFriendlyName() + "[]"; 
     } 

     return friendlyName; 
    } 

[TestFixture] 
public class TypeHelperTest 
{ 
    [Test] 
    public void TestGetFriendlyName() 
    { 
     Assert.AreEqual("string", typeof(string).FriendlyName()); 
     Assert.AreEqual("int[]", typeof(int[]).FriendlyName()); 
     Assert.AreEqual("int[][]", typeof(int[][]).FriendlyName()); 
     Assert.AreEqual("KeyValuePair<int, string>", typeof(KeyValuePair<int, string>).FriendlyName()); 
     Assert.AreEqual("Tuple<int, string>", typeof(Tuple<int, string>).FriendlyName()); 
     Assert.AreEqual("Tuple<KeyValuePair<object, long>, string>", typeof(Tuple<KeyValuePair<object, long>, string>).FriendlyName()); 
     Assert.AreEqual("List<Tuple<int, string>>", typeof(List<Tuple<int, string>>).FriendlyName()); 
     Assert.AreEqual("Tuple<short[], string>", typeof(Tuple<short[], string>).FriendlyName()); 
    } 
} 
+0

Bien, je l'utilise dans mon codegen maintenant aussi! – Karle

+0

Est-ce que cela compile? Je devais peaufiner un peu. Edité pour corrections. – Humberto

+2

Vous avez oublié Nullable. Pour alléguer les valeurs NULL, vous devez utiliser quelque chose comme ceci: 'if (type.GetGenericTypeDefinition() == typeof (Nullable <>)) Renvoyer type.GetGenericArguments(). First(). GetFriendlyName() +"? ";' –

0

Voici mon point de vue. Je n'ai pas mis le chèque en retrait puisque pour ce que je vois, il est toujours là. Vous pouvez l'ajouter si vous voulez mais j'aime garder les choses simples.

public static string GetFriendlyName(this Type type) 
{ 
    if (type.IsGenericType) 
    { 
     var name = type.Name.Substring(0, type.Name.IndexOf('`')); 
     var types = string.Join(",", type.GetGenericArguments().Select(GetFriendlyName)); 
     return $"{name}<{types}>"; 
    } 
    else 
    { 
     return type.Name; 
    } 
} 
Questions connexes