2010-11-15 20 views
29

Potrzebuję jakiś sposób, aby uzyskać nazwę typu, gdy type.IsGenericType = true.C# Uzyskaj nazwę typu ogólnego

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

czego chcę, to okno komunikatu do pop-up z List pokaz ... Jak mogę to zrobić?

Odpowiedz

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

W przypadku trzeba typ T typu generycznego jak '' Lista można użyć coś takiego 't.GetGenericArguments() [0] .Name'. Potrzebowałem tego jakiś czas temu i nie mogłem go nigdzie znaleźć. To zwróci 'string' w przypadku, gdy masz' List ' –

38

można zaimplementować metodę rozszerzenia aby uzyskać „przyjazny nazwa "typu", na przykład:

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

Z tego w projekcie, można powiedzieć:

MessageBox.Show(t.GetFriendlyName()); 

I wyświetli "List <String>".

Wiem, że OP nie wymagał ogólnych parametrów typu, ale wolę to w ten sposób. ;-)

Przestrzenie nazw i standard aliases for built-in types pozostawione jako ćwiczenie dla czytelnika.

+2

Z nowym wyglądem C#, możesz teraz napisać cały bit po sprawdzeniu backtick w jednej (choć długiej) linii, a to zajmie się również zagnieżdżonymi generycznymi: 'friendlyName + = $" <{string.Join (",", type.GetGenericArguments(). Wybierz (p => type.GetFriendlyName()))}> "' – joshcomley

3

Mam ulepszoną wersję yoyos do wykorzystania w generowaniu kodu. Należy zauważyć, że wszystkie typy są teraz określane jako pełna kwalifikowana => 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

My się na podejściu yoyo za. Zapewnia bardziej przyjazne nazwy dla prymitywów, obsługuje tablice i jest rekursywna do obsługi zagnieżdżonych generycznych. Również testy jednostkowe.

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

Dobrze, używam tego w moim także kodaner! – Karle

+0

Czy to się kompiluje? Musiałem trochę poprawić. Edytowane w celu korekty. – Humberto

+2

Zapomniałeś o Nullable. Aby upiększyć puste miejsca, powinieneś użyć czegoś takiego: 'if (type.GetGenericTypeDefinition() == typeof (Nullable <>)) typ zwrotu.GetGenericArguments(). First(). GetFriendlyName() +"? ";' –

0

Oto moje zdanie na ten temat. Nie odłożyłem kontroli od tyłu, ponieważ to, co widzę, zawsze tam jest. Możesz go dodać, jeśli chcesz, ale lubię zachować prostotę.

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