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

时间:2009-09-01 14:46:18

标签: c# .net reflection

我正在编写一个简单的代码生成应用程序来从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; }

提前致谢。

8 个答案:

答案 0 :(得分:46)

不 - 只需创建一个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(float), "float" },
    { typeof(double), "double" },
    { typeof(decimal), "decimal" },
    { typeof(object), "object" },
    { typeof(bool), "bool" },
    { typeof(char), "char" },
    { typeof(string), "string" },
    { typeof(void), "void" }
};

答案 1 :(得分:28)

严格来说,这不使用反射,但您可以使用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#别名的映射可能是最好的方法。)

答案 2 :(得分:8)

如果有人需要带有nullables的字典:

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

答案 3 :(得分:3)

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

答案 4 :(得分:2)

保持简单:

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

Type reflectedType;
string aliasedTypeName = aliasDict[reflectedType];

答案 5 :(得分: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?" }
    };
}

答案 6 :(得分:1)

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

答案 7 :(得分: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://docs.microsoft.com/en-us/dotnet/api/system.typecode?view=netstandard-1.3
自.Net 1.1以来一直存在

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

唯一的缺点是,如果要将Object别名为object,则需要额外检查。


如果您想知道为什么为什么存在,那么它可用于促进System.IConvertible的高效实现- 还公开了GetTypeCode()方法:
https://docs.microsoft.com/en-us/dotnet/api/system.iconvertible.gettypecode?view=netstandard-1.3

因此,从本质上讲,原始C#开发团队的某人决定在v1.1天内出于某种原因或其他原因决定公开,这可以看作是实现细节。也许这样,如果其他人也需要实施内置类型的性能摆弄,便可以利用它呢?

无论哪种方式,它自20多年来以来一直是该语言的一部分! :D


(我个人利用TypeCode建立了一个小型库,用于通用数字范围检查和其他特定于数字的元数据方法,例如,使用编译时未知的通用数字类型执行算术而无需使用反射或尝试捕获尝试。)


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