2010-11-15 25 views
29

Necesito alguna forma de obtener el nombre de un tipo, cuando type.IsGenericType = true.C# Get Generic Type Name

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

Lo que quiero, es un cuadro de mensaje para que aparezca con List que muestra ... ¿cómo puedo hacer eso?

Respuesta

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

En caso de que necesite el tipo T de un tipo genérico como '' Lista se puede usar algo como esto 't.GetGenericArguments() [0] .Name'. Necesitaba esto hace un tiempo y no pude encontrarlo en ningún lado. Esto devolverá 'cadena' en el caso de que tenga una' Lista ' –

38

Se puede implementar un método de extensión para obtener el "amigable nombre "de un tipo, como este:

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; 
    } 
} 

Con esto en su proyecto, ahora se puede decir:

MessageBox.Show(t.GetFriendlyName()); 

y se mostrará "Lista <cadena>".

Sé que OP no solicitó los parámetros de tipo genérico, pero lo prefiero de esa manera. ;-)

Namespaces y standard aliases for built-in types quedan como un ejercicio para el lector.

+2

Con la nueva belleza C#, ahora puede escribir todo el bit después de la marca de retroceso en una línea (aunque larga), y esto también tratará con genéricos anidados: 'friendlyName + = $" <{string.Join (",", type.GetGenericArguments(). Select (p => type.GetFriendlyName()))}> "' – joshcomley

3

he mejorado la versión de yoyos para el uso en Generación de código. Tenga en cuenta que ahora se hace referencia a todos los tipos full qualified => 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

Mi opinión sobre el enfoque de yoyo. Garantiza más nombres amigables para primitivos, maneja matrices y es recursivo para manejar genéricos anidados. También pruebas unitarias.

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, estoy usando esto en mi ¡Codegen ahora también! – Karle

+0

¿Esto compila? Tuve que retocar un poco. Editado para correcciones. – Humberto

+2

Has olvidado Nullable. Para embellecer elementos nulables, debe usar algo como esto: 'if (type.GetGenericTypeDefinition() == typeof (Nullable <>)) return type.GetGenericArguments(). First(). GetFriendlyName() +"? ";' –

0

Aquí está mi opinión sobre esto. No puse el cheque de contratiempo ya que, por lo que veo, siempre está ahí. Puede agregarlo si lo desea, pero me gusta mantener las cosas 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; 
    } 
}