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

前端 未结 5 2112
旧时难觅i
旧时难觅i 2021-02-07 23:46

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 d

相关标签:
5条回答
  • 2021-02-08 00:08

    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.

    0 讨论(0)
  • 2021-02-08 00:13

    Here's a way to do it by using Roslyn:

    using System;
    using System.Linq;
    using Roslyn.Scripting.CSharp;
    
    namespace ConsoleApplication
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine(GetType("int[,][,][][,][][]"));
                Console.WriteLine(GetType("Activator"));
                Console.WriteLine(GetType("List<int[,][,][][,][][]>"));
            }
    
            private static Type GetType(string type)
            {
                var engine = new ScriptEngine();
                new[] { "System" }
                    .ToList().ForEach(r => engine.AddReference(r));
                new[] { "System", "System.Collections.Generic" }
                    .ToList().ForEach(ns => engine.ImportNamespace(ns));
                return engine
                    .CreateSession()
                    .Execute<Type>("typeof(" + type + ")");
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-08 00:24

    Here's one way to do it:

    public Type GetType(string friendlyName)
    {
        var provider = new CSharpCodeProvider();
    
        var pars = new CompilerParameters
        {
            GenerateExecutable = false,
            GenerateInMemory = true
        };
    
        string code = "public class TypeFullNameGetter"
                    + "{"
                    + "     public override string ToString()"
                    + "     {"
                    + "         return typeof(" + friendlyName + ").FullName;"
                    + "     }"
                    + "}";
    
        var comp = provider.CompileAssemblyFromSource(pars, new[] { code });
    
        if (comp.Errors.Count > 0)
            return null;
    
        object fullNameGetter = comp.CompiledAssembly.CreateInstance("TypeFullNameGetter");
        string fullName = fullNameGetter.ToString();            
        return Type.GetType(fullName);
    }
    

    Then if you pass in "int", "int[]" etc you get the corresponding type back.

    0 讨论(0)
  • 2021-02-08 00:26

    Here's my stab at it. I approached it using two similar libraries:

    • Mono C# compiler-as-a-service
    • MS Roslyn C# compiler

    I think it's pretty clean and straightforward.

    Here I'm using Mono's C# compiler-as-a-service, namely the Mono.CSharp.Evaluator class. (It's available as a Nuget package named, unsurprisingly, Mono.CSharp)

    using Mono.CSharp;
    
        public static Type GetFriendlyType(string typeName)
        {
            //this class could use a default ctor with default sensible settings...
            var eval = new Mono.CSharp.Evaluator(new CompilerContext(
                                                     new CompilerSettings(),
                                                     new ConsoleReportPrinter()));
    
            //MAGIC! 
            object type = eval.Evaluate(string.Format("typeof({0});", typeName));
    
            return (Type)type;
        }
    

    Up next: The counterpart from "the friends in building 41" aka Roslyn...

    Later:

    Roslyn is almost as easy to install - once you figure out what's what. I ended up using Nuget package "Roslyn.Compilers.CSharp" (Or get it as a VS add-in). Just be warned that Roslyn requires a .NET 4.5 project.

    The code is even cleaner:

    using Roslyn.Scripting.CSharp;
    
        public static Type GetFriendlyType(string typeName)
        {
            ScriptEngine engine = new ScriptEngine();
            var type = engine.CreateSession()
                             .Execute<Type>(string.Format("typeof({0})", typeName));
            return type;
        }
    
    0 讨论(0)
  • 2021-02-08 00:32

    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..
    
    0 讨论(0)
提交回复
热议问题