GetType 返回 Int 而不是 System.Int32



GetType().ToString() 返回对象的全名。我想要您通常用于实例化该对象的名称,即 int 而不是 Int32。有没有办法做到这一点?

C# 有许多"类型",实际上是 .NET CLRTypes 的关键字别名。 在这种情况下,intSystem.Int32的 C# 别名,但其他 C# 类型也是如此,例如stringSystem.String的别名。

这意味着,当您深入了解反射并开始查看 CLRType对象时,您将找不到intstring或任何其他 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"

泛 型

.NET 类型系统中的泛型很有趣。 处理List<int>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))以获得有趣的结果。

GetType().ToString().FromDotNetTypeToCSharpType();

使用下面的扩展方法。我使用以下Microsoft参考为我在 c# 中所做的一些模板想出了类似的东西:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table

(可选)可以为快捷方式 null 语法传入类型是否可为 null 的布尔值。

/// <summary>Converts a .Net type name to a C# type name. It will remove the "System." namespace, if present,</summary>
public static string FromDotNetTypeToCSharpType(this string dotNetTypeName, bool isNull = false)
{
string cstype = "";
string nullable = isNull ? "?" : "";
string prefix = "System.";
string typeName = dotNetTypeName.StartsWith(prefix) ? dotNetTypeName.Remove(0, prefix.Length) : dotNetTypeName;
switch (typeName)
{
case "Boolean": cstype = "bool"; break;
case "Byte":    cstype = "byte"; break;
case "SByte":   cstype = "sbyte"; break;
case "Char":    cstype = "char"; break;
case "Decimal": cstype = "decimal"; break;
case "Double":  cstype = "double"; break;
case "Single":  cstype = "float"; break;
case "Int32":   cstype = "int"; break;
case "UInt32":  cstype = "uint"; break;
case "Int64":   cstype = "long"; break;
case "UInt64":  cstype = "ulong"; break;
case "Object":  cstype = "object"; break;
case "Int16":   cstype = "short"; break;
case "UInt16":  cstype = "ushort"; break;
case "String":  cstype = "string"; break;
default: cstype = typeName; break; // do nothing
}
return $"{cstype}{nullable}";
}

这使用 CSharpCodeProvider,处理泛型并在需要时添加命名空间。

using System;
using System.CodeDom;
using System.Collections.Generic;
using Microsoft.CSharp;
//...
private string GetFriendlyTypeName(Type type)
{
using (var p = new CSharpCodeProvider())
{
var r = new CodeTypeReference(type);
return p.GetTypeOutput(r);
}
}

在应得的地方给予信用。

相关内容

最新更新