我需要以代码中声明的形式获取泛型类型的名称。例如:对于List,我想获取字符串“List“。标准属性Type.Name在这种情况下返回“List`1”。编辑:示例已修复
c90pui9n1#
使用内置函数和Linq,可以编写
static string PrettyTypeName(Type t) { if (t.IsArray) { return PrettyTypeName(t.GetElementType()) + "[]"; } if (t.IsGenericType) { return string.Format( "{0}<{1}>", t.Name.Substring(0, t.Name.LastIndexOf("`", StringComparison.InvariantCulture)), string.Join(", ", t.GetGenericArguments().Select(PrettyTypeName))); } return t.Name; }
字符串注意:在C#4.0之前的版本中,string.Join需要显式的.ToArray():
string.Join
.ToArray()
string.Join(", ", t.GetGenericArguments().Select(PrettyTypeName).ToArray()));
型
a7qyws3x2#
好吧,我做了一堆研究,发现typeof(List)有“GetGenericArguments”,它会让你得到子名称。所以我会这样做(对于1个泛型类型,如果它是一个multiple,它会采取循环或其他方式。如果需要,我可以发布一个函数。下面是一个函数,它使用多个泛型参数来处理“嵌套”泛型类型。再次编辑以使用Aggregate函数:
static string GetFullName(Type t) { if (!t.IsGenericType) return t.Name; StringBuilder sb=new StringBuilder(); sb.Append(t.Name.Substring(0, t.Name.LastIndexOf("`"))); sb.Append(t.GetGenericArguments().Aggregate("<", delegate(string aggregate,Type type) { return aggregate + (aggregate == "<" ? "" : ",") + GetFullName(type); } )); sb.Append(">"); return sb.ToString(); }
字符串
yzuktlbb3#
这不是很难;-)好吧,我会咬. g 下面的一个递归地工作,并显示原始类型w/o命名空间(就像OP写的那样):
static string PrettyPrintGenericTypeName(Type typeRef) { var rootType = typeRef.IsGenericType ? typeRef.GetGenericTypeDefinition() : typeRef; var cleanedName = rootType.IsPrimitive ? rootType.Name : rootType.ToString(); if (!typeRef.IsGenericType) return cleanedName; else return cleanedName.Substring(0, cleanedName.LastIndexOf('`')) + typeRef.GetGenericArguments() .Aggregate("<", (r, i) => r + (r != "<" ? ", " : null) + PrettyPrintGenericTypeName(i)) + ">"; }
字符串生成的cleanedName如下所示:System.Collections.Generic.Dictionary<System.Collections.Generic.List<Int32>, ConsoleApplication2.Program+SomeType>
System.Collections.Generic.Dictionary<System.Collections.Generic.List<Int32>, ConsoleApplication2.Program+SomeType>
a7qyws3x4#
老问题了,但我今天只需要这个。所以我写了一个扩展方法,可以输出漂亮的C#格式的泛型名称,可以处理多级嵌套泛型类型。
using System; using System.Text; public static class TypeExtensions { public static string GetNiceName(this Type type, bool useFullName = false) { if (!type.IsGenericType) { return type.Name; } var typeNameBuilder = new StringBuilder(); GetNiceGenericName(typeNameBuilder, type, useFullName); return typeNameBuilder.ToString(); } static void GetNiceGenericName(StringBuilder sb, Type type, bool useFullName) { if (!type.IsGenericType) { sb.Append(useFullName ? type.FullName : type.Name); return; } var typeDef = type.GetGenericTypeDefinition(); var typeName = useFullName ? typeDef.FullName : typeDef.Name; sb.Append(typeName); sb.Length -= typeName.Length - typeName.LastIndexOf('`'); sb.Append('<'); foreach (var typeArgument in type.GenericTypeArguments) { GetNiceGenericName(sb, typeArgument, useFullName); sb.Append(", "); } sb.Length -= 2; sb.Append('>'); } }
c3frrgcw5#
如果您不删除命名空间名称,只需说:
Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">");
字符串如果你这样做,说:
Regex.Replace(Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">"), @"\w+\.", "")
2guxujil6#
另一个例子,我只是写自己在这里绊倒之前。
private string PrettyPrintGenericTypeName(Type p) { if (p.IsGenericType) { var simpleName = p.Name.Substring(0, p.Name.IndexOf('`')); var genericTypeParams = p.GenericTypeArguments.Select(PrettyPrintGenericTypeName).ToList(); return string.Format("{0}<{1}>", simpleName, string.Join(", ", genericTypeParams)); } else { return p.Name; } }
nnvyjq4y7#
几天前我遇到了同样的问题,我写了自己的扩展方法。这段代码适用于普通类型和“可空引用类型”。我不是100%确信它在所有情况下都能正常工作,但像这样的类型工作得很好:
public IDictionary<MyClass?[][], Dictionary<object?,int?[,]?>>? Dummy { get; set; }
字符串这几乎完美地满足了我的需求:
public static class ReflectionExtensions { public static string ToReadableTypeString(this PropertyInfo property, bool useFullnames = false, bool useInternalTypeNames= true) { return ToReadableTypeStringInternal(property.PropertyType, new NullabilityInfoContext().Create(property), useFullnames, useInternalTypeNames); } public static string ToReadableTypeString(this Type type, NullabilityInfo? nullabilityInfo = null, bool useFullnames = false, bool useInternalTypeNames= true) { return ToReadableTypeStringInternal(type, nullabilityInfo, useFullnames, useInternalTypeNames); } private static string ToReadableTypeStringInternal(Type type,NullabilityInfo? nullabilityInfo, bool useFullnames, bool useInternalTypeNames) { if (type == null) { throw new ArgumentNullException(nameof(type)); } string suffix; var underlyingType = Nullable.GetUnderlyingType(type); if (underlyingType != null) { type = underlyingType; suffix = "?"; } else { suffix = nullabilityInfo?.ReadState == NullabilityState.Nullable ? "?" : ""; } if (useInternalTypeNames) { if (type == typeof(string)) { return "string"+suffix; } if (type == typeof(sbyte)) { return "sbyte"+suffix; } if (type == typeof(byte)) { return "byte"+suffix; } if (type == typeof(short)) { return "short"+suffix; } if (type == typeof(ushort)) { return "ushort"+suffix; } if (type == typeof(int )) { return "int"+suffix; } if (type == typeof(uint)) { return "uint"+suffix; } if (type == typeof(long)) { return "long"+suffix; } if (type == typeof(ulong )) { return "ulong"+suffix; } if (type == typeof(nint )) { return "nint"+suffix; } if (type == typeof(nuint)) { return "nuint"+suffix; } if (type == typeof(float)) { return "float"+suffix; } if (type == typeof(double)) { return "double"+suffix; } if (type == typeof(decimal)) { return "decimal"+suffix; } if (type == typeof(bool)) { return "bool"+suffix; } if (type == typeof(char)) { return "char"+suffix; } if (type == typeof(object)) { return "object"+suffix; } } if (type.IsArray) { var sb = new StringBuilder(ToReadableTypeStringInternal(type.GetElementType()!, nullabilityInfo?.ElementType, useFullnames, useInternalTypeNames)); if (type.IsVariableBoundArray) { sb.Append('['); sb.Append(new string(',',type.GetArrayRank()-1)); sb.Append(']'); } else { for (var i = 0; i < type.GetArrayRank(); i++) { sb.Append("[]"); } } return sb+suffix; } if (type.IsGenericType) { return (useFullnames?(type.FullName??type.Name):type.Name).Split("`").First() + "<" + string.Join(",", type.GenericTypeArguments.Select((type1,index) => ToReadableTypeStringInternal(type1,nullabilityInfo?.GenericTypeArguments[index], useFullnames, useInternalTypeNames))) + ">"; } return (useFullnames?(type.FullName??type.Name):type.Name)+suffix; } }
vsaztqbk8#
好吧,那是因为.NET中类型的名称实际上是List'1。"'1”是泛型的所谓arity,它告诉你有多少类型参数。它是必要的,这样你就可以创建一个以上的泛型类型,具有相同的“名称”,但不同数量的泛型类型参数。例如,有一个以上的类型“称为”System.xml。这些类型的真实的名称是System.xml '1、System.xml' 2、System.xml '3等。所以,如果你知道你的类型是泛型的,你可以假设在名称的末尾有'XX',所以你可以把这部分剪掉,比如这样:
string strTypeName = typeof(List<>).Name.Substring(0, typeof(List<>).Name.LastIndexOf("`"));
字符串PS:请将“”替换为“”。
8条答案
按热度按时间c90pui9n1#
使用内置函数和Linq,可以编写
字符串
注意:在C#4.0之前的版本中,
string.Join
需要显式的.ToArray()
:型
a7qyws3x2#
好吧,我做了一堆研究,发现typeof(List)有“GetGenericArguments”,它会让你得到子名称。所以我会这样做(对于1个泛型类型,如果它是一个multiple,它会采取循环或其他方式。如果需要,我可以发布一个函数。
下面是一个函数,它使用多个泛型参数来处理“嵌套”泛型类型。再次编辑以使用Aggregate函数:
字符串
yzuktlbb3#
这不是很难;-)
好吧,我会咬. g 下面的一个递归地工作,并显示原始类型w/o命名空间(就像OP写的那样):
字符串
生成的cleanedName如下所示:
System.Collections.Generic.Dictionary<System.Collections.Generic.List<Int32>, ConsoleApplication2.Program+SomeType>
a7qyws3x4#
老问题了,但我今天只需要这个。所以我写了一个扩展方法,可以输出漂亮的C#格式的泛型名称,可以处理多级嵌套泛型类型。
字符串
c3frrgcw5#
如果您不删除命名空间名称,只需说:
字符串
如果你这样做,说:
型
2guxujil6#
另一个例子,我只是写自己在这里绊倒之前。
字符串
nnvyjq4y7#
几天前我遇到了同样的问题,我写了自己的扩展方法。
这段代码适用于普通类型和“可空引用类型”。
我不是100%确信它在所有情况下都能正常工作,但像这样的类型工作得很好:
字符串
这几乎完美地满足了我的需求:
型
vsaztqbk8#
好吧,那是因为.NET中类型的名称实际上是List'1。"'1”是泛型的所谓arity,它告诉你有多少类型参数。
它是必要的,这样你就可以创建一个以上的泛型类型,具有相同的“名称”,但不同数量的泛型类型参数。
例如,有一个以上的类型“称为”System.xml。这些类型的真实的名称是System.xml '1、System.xml' 2、System.xml '3等。
所以,如果你知道你的类型是泛型的,你可以假设在名称的末尾有'XX',所以你可以把这部分剪掉,比如这样:
字符串
PS:请将“”替换为“”。