【发布时间】:2010-12-04 17:21:34
【问题描述】:
我需要以代码中声明的形式获取泛型类型的名称。
例如:
对于 List
编辑:示例已修复
【问题讨论】:
标签: c# .net reflection
我需要以代码中声明的形式获取泛型类型的名称。
例如:
对于 List
编辑:示例已修复
【问题讨论】:
标签: c# .net reflection
嗯,这是因为 .NET 中的类型名称实际上是 List'1。 “'1”是泛型的所谓arity,它告诉你有多少类型参数。
这样您就可以创建超过 1 个具有相同“名称”但泛型类型参数数量不同的泛型类型。
例如,有不止一种类型“称为”System.Action。它们的真实名称是 System.Action'1、System.Action'2、System.Action'3 等。
所以,如果你知道你的类型是通用的,你可以假设名字的末尾有这个 'XX,所以你可以把这部分删掉,例如这样:
string strTypeName = typeof(List<>).Name.Substring(0, typeof(List<>).Name.LastIndexOf("`"));
PS:请用`替换'。
【讨论】:
好的,我做了很多研究,发现 typeof(List) 有“GetGenericArguments”,它可以让你得到子名称。所以我会这样做(对于 1 个泛型类型,如果它是一个 multi 它将需要一个循环或其他东西。如果需要,我可以发布一个函数。
这是一个使用多个泛型参数来处理“嵌套”泛型类型的函数。再次编辑以使用 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();
}
【讨论】:
这并不难。 ;-)
好吧,我会咬一口... g 下面的一个循环工作并显示没有命名空间的原始类型(就像 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))
+ ">";
}
生成的 cleanName 如下所示:System.Collections.Generic.Dictionary<System.Collections.Generic.List<Int32>, ConsoleApplication2.Program+SomeType>
【讨论】:
使用内置函数和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(", ", t.GetGenericArguments().Select(PrettyTypeName).ToArray()));
【讨论】:
t.GetGenericArguments().Select(PrettyTypeName) 给出编译器错误“cannot convert from 'System.Collections.Generic.IEnumerable.ToArray()。添加到答案作为替代。
PrettyTypeName(typeof(ICollection<Tuple<string, int, Tuple<ICollection<string>,IList>[]>[]>))。必须添加if (t.IsArray) return PrettyTypeName(t.GetElementType()) + "[]";。
另一个例子是我在遇到这里之前自己写的。
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;
}
}
【讨论】:
老问题,但我今天才需要这个。所以我写了一个扩展方法,它可以输出漂亮的 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('>');
}
}
【讨论】:
如果您不删除命名空间名称,只需说:
Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">");
如果你这样做了,说:
Regex.Replace(Regex.Replace(""+@type, @"`\d+\[", "<").Replace("]", ">"), @"\w+\.", "")
【讨论】: