C# 有许多“类型”,它们实际上是 .NET CLR 的关键字别名Type
s。在这种情况下,int
是 C# 的别名System.Int32
,但其他 C# 类型也是如此,例如string
这是一个别名System.String
.
这意味着当您深入了解反射并开始查看 CLRType
你找不到的物体int
, string
或任何其他 C# 类型别名,因为 .NET 和 CLR 不知道它们......也不应该知道它们。
如果您想从 CLR 类型转换为 C# 别名,您必须自己通过查找来完成。像这样的东西:
// This is the set of types from the C# keyword list.
static Dictionary<Type, string> _typeAlias = new Dictionary<Type, string>
{
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(float), "float" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(object), "object" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(string), "string" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
// Yes, this is an odd one. Technically it's a type though.
{ typeof(void), "void" }
};
static string TypeNameOrAlias(Type type)
{
// Lookup alias for type
if (_typeAlias.TryGetValue(type, out string alias))
return alias;
// Default to CLR type name
return type.Name;
}
对于简单的类型来说,效果很好。泛型、数组和Nullable
多做一点工作。数组和Nullable
值的递归处理如下:
static string TypeNameOrAlias(Type type)
{
// Handle nullable value types
var nullbase = Nullable.GetUnderlyingType(type);
if (nullbase != null)
return TypeNameOrAlias(nullbase) + "?";
// Handle arrays
if (type.BaseType == typeof(System.Array))
return TypeNameOrAlias(type.GetElementType()) + "[]";
// Lookup alias for type
if (_typeAlias.TryGetValue(type, out string alias))
return alias;
// Default to CLR type name
return type.Name;
}
这将处理类似的事情:
Console.WriteLine(TypeNameOrAlias(typeof(int?[][])));
如果您需要泛型,它们会涉及更多基本相同的过程。扫描通用参数列表并在该过程中递归运行类型。
嵌套类型
当你跑步时TypeNameOrAlias
在嵌套类型上,结果只是特定类型的名称,而不是您需要指定的从声明它的类型外部使用它的完整路径:
public class Outer
{
public class Inner
{
}
}
// TypeNameOrAlias(typeof(Outer.Inner)) == "Inner"
这解决了这个问题:
static string GetTypeName(Type type)
{
string name = TypeNameOrAlias(type);
if (type.DeclaringType is Type dec)
{
return $"{GetTypeName(dec)}.{name}";
}
return name;
}
// GetTypeName(typeof(Outer.Inner)) == "Outer.Inner"
Generics
.NET 类型系统中的泛型很有趣。处理诸如此类的事情相对容易List<int>
or Dictionary<int, string>
或类似的。将其插入到顶部TypeNameOrAlias
:
// Handle generic types
if (type.IsGenericType)
{
string name = type.Name.Split('`').FirstOrDefault();
IEnumerable<string> parms =
type.GetGenericArguments()
.Select(a => type.IsConstructedGenericType ? TypeNameOrAlias(a) : a.Name);
return $"{name}<{string.Join(",", parms)}>";
}
现在您将获得正确的结果,例如TypeNameOrAlias(typeof(Dictionary<int, string>))
等等。它还处理泛型类型定义:TypeNameOrAlias(typeof(Dictionary<,>))
将返回Dictionary<TKey,TValue>
.
当您将类嵌套在泛型中时,事情会变得困难。尝试GetTypeName(typeof(Dictionary<int, string>.KeyCollection))
以获得有趣的结果。