Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert "C# friendly type" name to actual type: "int" => typeof(int)

I want to get a System.Type given a string that specifies a (primitive) type's C# friendly name, basically the way the C# compiler does when reading C# source code.

I feel the best way to describe what I'm after is in the form of an unit-test.

My hope is that a general technique exists that can make all the below assertions pass, rather than try to hard-code special cases for special C# names.

Type GetFriendlyType(string typeName){ ...??... }

void Test(){
    // using fluent assertions

    GetFriendlyType( "bool" ).Should().Be( typeof(bool) );
    GetFriendlyType( "int" ).Should().Be( typeof(int) );

    // ok, technically not a primitive type... (rolls eyes)
    GetFriendlyType( "string" ).Should().Be( typeof(string) ); 

    // fine, I give up!
    // I want all C# type-aliases to work, not just for primitives
    GetFriendlyType( "void" ).Should().Be( typeof(void) );
    GetFriendlyType( "decimal" ).Should().Be( typeof(decimal) ); 

    //Bonus points: get type of fully-specified CLR types
    GetFriendlyName( "System.Activator" ).Should().Be(typeof(System.Activator));

    //Hi, Eric Lippert! 
    // Not Eric? https://stackoverflow.com/a/4369889/11545
    GetFriendlyName( "int[]" ).Should().Be( typeof(int[]) ); 
    GetFriendlyName( "int[,]" ).Should().Be( typeof(int[,]) ); 
    //beating a dead horse
    GetFriendlyName( "int[,][,][][,][][]" ).Should().Be( typeof(int[,][,][][,][][]) ); 
}

What I tried so far:

This question is the complement of an older question of mine asking how to get the "friendly name" from a type.

The answer to that question is: use CSharpCodeProvider

using (var provider = new CSharpCodeProvider())
{
    var typeRef = new CodeTypeReference(typeof(int));
    string friendlyName = provider.GetTypeOutput(typeRef);
}

I can't figure out how (or if possible) to do it the other way around and get the actual C# type from the CodeTypeReference (it also has a ctor that takes a string)

var typeRef = new CodeTypeReference(typeof(int));
like image 343
Cristian Diaconescu Avatar asked Jun 07 '13 12:06

Cristian Diaconescu


2 Answers

Alias names like 'int','bool' etc. are not part of .NET Framework. Internally they are converted into System.Int32, System.Boolean etc. Type.GetType("int") should return you null. Best way to appoach this is by having a dictionary to map alias with their type e.g.

        Dictionary<string, Type> PrimitiveTypes = new Dictionary<string, Type>();
        PrimitiveTypes.Add("int", typeof(int));
        PrimitiveTypes.Add("long", typeof(long));
        etc.etc..
like image 118
Yogee Avatar answered Sep 23 '22 14:09

Yogee


Don't you have most of if worked out already?

The following gives you all built-in C# types as per http://msdn.microsoft.com/en-us/library/ya5y69ds.aspx, plus void.

using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.Reflection;

namespace CSTypeNames
{
    class Program
    {
        static void Main(string[] args)
        {
            // Resolve reference to mscorlib.
            // int is an arbitrarily chosen type in mscorlib
            var mscorlib = Assembly.GetAssembly(typeof(int));

            using (var provider = new CSharpCodeProvider())
            {
                foreach (var type in mscorlib.DefinedTypes)
                {
                    if (string.Equals(type.Namespace, "System"))
                    {
                        var typeRef = new CodeTypeReference(type);
                        var csTypeName = provider.GetTypeOutput(typeRef);

                        // Ignore qualified types.
                        if (csTypeName.IndexOf('.') == -1)
                        {
                            Console.WriteLine(csTypeName + " : " + type.FullName);
                        }
                    }
                }
            }

            Console.ReadLine();
        }
    }
}

This is based on several assumptions which I believe to be correct as at the time of writing:

  • All built-in C# types are part of mscorlib.dll.
  • All built-in C# types are aliases of types defined in the System namespace.
  • Only built-in C# types' names returned by the call to CSharpCodeProvider.GetTypeOutput do not have a single '.' in them.

Output:

object : System.Object
string : System.String
bool : System.Boolean
byte : System.Byte
char : System.Char
decimal : System.Decimal
double : System.Double
short : System.Int16
int : System.Int32
long : System.Int64
sbyte : System.SByte
float : System.Single
ushort : System.UInt16
uint : System.UInt32
ulong : System.UInt64
void : System.Void

Now I just have to sit and wait for Eric to come and tell me just how wrong I am. I have accepted my fate.

like image 43
Kirill Shlenskiy Avatar answered Sep 24 '22 14:09

Kirill Shlenskiy