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));
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..
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:
System
namespace.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With