有没有办法通过反射获取类型的别名?

问题描述 投票:0回答:8

我正在编写一个简单的代码生成应用程序,以从 DB2 数据库模式构建 POCO。 我知道这并不重要,但我更喜欢使用类型别名而不是实际的系统类型名称(如果可用),即“int”而不是“Int32”。 有没有一种方法可以使用反射来获取类型的别名而不是实际类型?

//Get the type name
var typeName = column.DataType.Name;

//If column.DataType is, say, Int64, I would like the resulting property generated
//in the POCO to be...

public long LongColumn { get; set; }

//rather than what I get now using the System.Reflection.MemberInfo.Name property:

public Int64 LongColumn { get; set; }
c# .net reflection
8个回答
61
投票

不 - 只需创建一个

Dictionary<Type,string>
将所有类型映射到它们的别名。这是一个固定的集合,所以并不难做到:

private static readonly Dictionary<Type, string> Aliases =
    new Dictionary<Type, string>()
{
    { typeof(byte), "byte" },
    { typeof(sbyte), "sbyte" },
    { typeof(short), "short" },
    { typeof(ushort), "ushort" },
    { typeof(int), "int" },
    { typeof(uint), "uint" },
    { typeof(long), "long" },
    { typeof(ulong), "ulong" },
    { typeof(nint), "nint" },
    { typeof(nuint), "nuint" },
    { typeof(float), "float" },
    { typeof(double), "double" },
    { typeof(decimal), "decimal" },
    { typeof(object), "object" },
    { typeof(bool), "bool" },
    { typeof(char), "char" },
    { typeof(string), "string" },
    { typeof(void), "void" }
};

32
投票

严格来说,这不使用反射,但您可以使用 CodeDOM 获取类型的别名:

Type t = column.DataType;    // Int64

string typeName;
using (var provider = new CSharpCodeProvider())
{
    var typeRef = new CodeTypeReference(t);
    typeName = provider.GetTypeOutput(typeRef);
}

Console.WriteLine(typeName);    // long

(话虽如此,我认为建议您只使用从 CLR 类型到 C# 别名的映射的其他答案可能是使用此答案的最佳方法。)


13
投票

如果有人需要带有可空值的字典:

private static readonly Dictionary<Type, string> Aliases = new Dictionary<Type, string>()
    {
        { typeof(byte), "byte" },
        { typeof(sbyte), "sbyte" },
        { typeof(short), "short" },
        { typeof(ushort), "ushort" },
        { typeof(int), "int" },
        { typeof(uint), "uint" },
        { typeof(long), "long" },
        { typeof(ulong), "ulong" },
        { typeof(float), "float" },
        { typeof(double), "double" },
        { typeof(decimal), "decimal" },
        { typeof(object), "object" },
        { typeof(bool), "bool" },
        { typeof(char), "char" },
        { typeof(string), "string" },
        { typeof(void), "void" },
        { typeof(Nullable<byte>), "byte?" },
        { typeof(Nullable<sbyte>), "sbyte?" },
        { typeof(Nullable<short>), "short?" },
        { typeof(Nullable<ushort>), "ushort?" },
        { typeof(Nullable<int>), "int?" },
        { typeof(Nullable<uint>), "uint?" },
        { typeof(Nullable<long>), "long?" },
        { typeof(Nullable<ulong>), "ulong?" },
        { typeof(Nullable<float>), "float?" },
        { typeof(Nullable<double>), "double?" },
        { typeof(Nullable<decimal>), "decimal?" },
        { typeof(Nullable<bool>), "bool?" },
        { typeof(Nullable<char>), "char?" }
    };

4
投票

基于上述 2 个使用字典的答案,我编写了 2 个基本扩展方法,可能有助于清理使用。在您的项目中包含此类,您只需调用类型上的 Alias() 或 AliasOrName() 方法即可使用它,如下所示。

使用示例;

        // returns int
        string intAlias = typeof(Int32).Alias();
        // returns int
        string intAliasOrName = typeof(Int32).AliasOrName();
        // returns string.empty
        string dateTimeAlias = typeof(DateTime).Alias();
        // returns DateTime
        string dateTimeAliasOrName = typeof(DateTime).AliasOrName();

实施;

public static class TypeExtensions
{
    public static string Alias(this Type type)
    {
        return TypeAliases.ContainsKey(type) ?
            TypeAliases[type] : string.Empty;
    }

    public static string AliasOrName(this Type type)
    {
        return TypeAliases.ContainsKey(type) ?
            TypeAliases[type] : type.Name;
    }

    private static readonly Dictionary<Type, string> TypeAliases = new Dictionary<Type, string>
    {
        { typeof(byte), "byte" },
        { typeof(sbyte), "sbyte" },
        { typeof(short), "short" },
        { typeof(ushort), "ushort" },
        { typeof(int), "int" },
        { typeof(uint), "uint" },
        { typeof(long), "long" },
        { typeof(ulong), "ulong" },
        { typeof(float), "float" },
        { typeof(double), "double" },
        { typeof(decimal), "decimal" },
        { typeof(object), "object" },
        { typeof(bool), "bool" },
        { typeof(char), "char" },
        { typeof(string), "string" },
        { typeof(void), "void" },
        { typeof(byte?), "byte?" },
        { typeof(sbyte?), "sbyte?" },
        { typeof(short?), "short?" },
        { typeof(ushort?), "ushort?" },
        { typeof(int?), "int?" },
        { typeof(uint?), "uint?" },
        { typeof(long?), "long?" },
        { typeof(ulong?), "ulong?" },
        { typeof(float?), "float?" },
        { typeof(double?), "double?" },
        { typeof(decimal?), "decimal?" },
        { typeof(bool?), "bool?" },
        { typeof(char?), "char?" }
    };
}

4
投票
public string GetAlias(Type t)
{
    string typeName = "";
    using (var provider = new CSharpCodeProvider())
    {
        var typeRef = new CodeTypeReference(t);
        typeName = provider.GetTypeOutput(typeRef);
    }
    return typeName;
}

2
投票

保持简单:

var aliasDict = new Dictionary<Type, string>() {
    { typeof(int), "int" },
    { typeof(long), "long" },
    // etc
}

Type reflectedType;
string aliasedTypeName = aliasDict[reflectedType];

1
投票

我认为没有。 别名完全是一个特定于您使用的特定 .NET 语言的编译时概念。 一旦您反映并查看类型,您将看到对象的真实 .NET 类型。


1
投票

字典的答案很灵活,但如果我们只想要基本类型,我们可以做得更好:

public static class TypeNameExtensions
{
    private static readonly string[] TypeAliases = {
        "void",     // 0
        null,       // 1 (any other type)
        "DBNull",   // 2
        "bool",     // 3
        "char",     // 4
        "sbyte",    // 5
        "byte",     // 6
        "short",    // 7
        "ushort",   // 8
        "int",      // 9
        "uint",     // 10
        "long",     // 11
        "ulong",    // 12
        "float",    // 13
        "double",   // 14
        "decimal",  // 15
        null,       // 16 (DateTime)
        null,       // 17 (-undefined- presumably TimeSpan in some pre-1.0 C# alpha)
        "string",   // 18
    };

如果不需要支持数组类型:

    public static bool TryGetNameAlias(this Type t, out string alias)
        => (alias = TypeAliases[(int)Type.GetTypeCode(t)]) != null && !t.IsEnum;

编辑:如果需要支持数组类型:

    public static bool TryGetNameAlias(this Type t, out string alias)
    {
        string arrayBrackets = null;
        while (t.IsArray)
        {
            arrayBrackets += "[" + new string(',', t.GetArrayRank() - 1) + "]";
            t = t.GetElementType();
        }
        alias = TypeAliases[(int)Type.GetTypeCode(t)];
        if (alias == null || t.IsEnum)
            return false;
        alias += arrayBrackets;
        return true;
    }
}

这是基于

TypeCode
枚举:
https://learn.microsoft.com/en-us/dotnet/api/system.typecode?view=netstandard-1.3
自 .Net 1.1 以来就已经存在了

应该比字典更快,因为它使用 TypeCode 作为索引直接跳转到数组中。

唯一的缺点是,如果我们想将

Object
别名为
object
,我们需要额外检查。


如果您想知道 为什么 这个枚举存在,它用于促进

System.IConvertible
的高性能实现 - 公开了
GetTypeCode()
方法:
https://learn.microsoft.com/en-us/dotnet/api/system.iconvertible.gettypecode?view=netstandard-1.3

因此,从本质上讲,它可以被视为原始 C# 开发团队中的某人在 v1.1 时代出于某种原因决定公开的实现细节。也许这样,如果其他人也需要对内置类型进行高性能摆弄,他们就可以利用它?

无论如何,它从早期就已经成为该语言的一部分,至今已有 20 多年了! :D


(就我个人而言,我利用

TypeCode
构建了一个小型库,用于通用数值范围检查和其他特定于数字的元数据方法,例如使用编译时未知的通用数值类型执行算术,而不使用反射或 try-catch 尝试。 )


编辑:更新为支持数组类型(包括嵌套和多维)。
编辑:更新以正确处理

enum
类型。

© www.soinside.com 2019 - 2024. All rights reserved.