31

I'm writing a simple code generation application to build POCO's from a DB2 database schema. I know it doesn't matter, but I prefer to use type aliases rather than the actual system type name if they are available, i.e., "int" rather than "Int32." Is there a way using reflection that I can get a type's alias rather than it's the actual type?

//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; }
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
AJ.
  • 16,368
  • 20
  • 95
  • 150

8 Answers8

62

Nope - just create a Dictionary<Type,string> to map all of the types to their aliases. It's a fixed set, so it's not hard to do:

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" }
};
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
33

This doesn't use reflection, strictly speaking, but you can get to the type's alias by using 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

(Having said that, I think that the other answers suggesting that you just use a mapping from CLR types to C# aliases are probably the best way to go with this one.)

LukeH
  • 263,068
  • 57
  • 365
  • 409
12

In case someone needs the dictionary with 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?" }
    };
rubenmch
  • 143
  • 1
  • 5
4

Based on the above 2 answers for using a Dictionary, I've written 2 basic extension methods that might help clean up the use a bit. Including this class in your project you will be able to use it simply by calling the Alias() or AliasOrName() methods on the type as shown below.

Example usage;

        // 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();

The implementation;

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?" }
    };
}
mbrdev
  • 584
  • 5
  • 9
4
public string GetAlias(Type t)
{
    string typeName = "";
    using (var provider = new CSharpCodeProvider())
    {
        var typeRef = new CodeTypeReference(t);
        typeName = provider.GetTypeOutput(typeRef);
    }
    return typeName;
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Blue Joy
  • 335
  • 1
  • 7
2

Keep it simple:

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

Type reflectedType;
string aliasedTypeName = aliasDict[reflectedType];
jason
  • 236,483
  • 35
  • 423
  • 525
1

I don't think there is. The alias is completly a compile time concept specific to the paticular .NET language you use. Once you reflect and view the type you will see the true .NET type of the object.

Matthew Manela
  • 16,572
  • 3
  • 64
  • 66
1

The dictionary answers are flexible, but we can do one better if we want basic types only:

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

If you don't need to support array types:

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

Edit: If you need to support array types:

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

This is based on the TypeCode enum:
https://learn.microsoft.com/en-us/dotnet/api/system.typecode?view=netstandard-1.3
which has been around since .Net 1.1

Should be faster than a dictionary since it jumps straight into an array using the TypeCode as index.

The only downside is that we would need an extra check if we want to alias Object as object.


If you are wondering why this enum exist, it's used to facilitate performant implementation of System.IConvertible - which also exposes the GetTypeCode() method:
https://learn.microsoft.com/en-us/dotnet/api/system.iconvertible.gettypecode?view=netstandard-1.3

So in essence it could be seen as an implementation detail that someone one the original C# dev team decided to make public for one reason or another all the way back in the v1.1 days. Perhaps so that others could take advantage of it if they too needed to implement performant fiddling about with the built in types?

Either way it has been part of the language since its early beginnings, over 20 years now! :D


(Personally I have leveraged TypeCode to built a small library for generic numeric range checking and other numeric-specific metadata methods, e.g. performing arithmetic using compile-time unknown generic numeric types without the use of reflection or try-catch attempts.)


Edit: Updated to support array types (including nested and multi-dimensional).
Edit: Updated to properly handle enum types.

AnorZaken
  • 1,916
  • 1
  • 22
  • 34