.net GetType返回Int而不是System.Int32

fdx2calv  于 2023-04-13  发布在  .NET
关注(0)|答案(3)|浏览(140)

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

jm2pwxwz

jm2pwxwz1#

C#有许多“类型”,它们实际上是.NET CLR Type s的关键字别名。在本例中,intSystem.Int32的C#别名,但其他C#类型也是如此,如stringSystem.String的别名。
这意味着,当你深入了解反射并开始查看CLR Type对象时,你不会找到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))会得到一个有趣的结果。

polkgigr

polkgigr2#

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

使用下面的扩展方法。我用下面的微软参考资料为我在c#中做的一些模板做了一些类似的事情:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table
可选地,可以为快捷方式可空语法传入类型是否可空的布尔值。

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

    }
fnvucqvd

fnvucqvd3#

它使用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);
    }
}

credit它的到期日。

相关问题