将"C#friendly type"转换为实际类型:"int"=> typeof(int)

Cri*_*scu 12 .net c# reflection types

我想得到一个System.Type给定的string指定(原始)类型的C#友好名称,基本上是C#编译器在读取C#源代码时的方式.

我觉得描述我所追求的是以单元测试形式出现的最佳方式.

我希望存在一种通用技术可以使所有下面的断言通过,而不是试图对特殊C#名称的特殊情况进行硬编码.

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[,][,][][,][][]) ); 
}
Run Code Online (Sandbox Code Playgroud)

到目前为止我尝试了什么:

这个问题是我的一个老问题的补充,询问如何从一个类型获得"友好名称".

这个问题的答案是:使用 CSharpCodeProvider

using (var provider = new CSharpCodeProvider())
{
    var typeRef = new CodeTypeReference(typeof(int));
    string friendlyName = provider.GetTypeOutput(typeRef);
}
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何(或者如果可能)以相反的方式执行它并从中获取实际的C#类型CodeTypeReference(它还有一个需要的ctor string)

var typeRef = new CodeTypeReference(typeof(int));
Run Code Online (Sandbox Code Playgroud)

Kir*_*kiy 11

你有没有大部分已经解决了吗?

下面给你所有内置C#类型按http://msdn.microsoft.com/en-us/library/ya5y69ds.aspx,加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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这基于几个假设,我认为在撰写本文时这些假设是正确的:

  • 所有内置的C#类型都是mscorlib.dll的一部分.
  • 所有内置C#类型都是System命名空间中定义的类型的别名.
  • 只有通过调用返回的内置C#类型名称CSharpCodeProvider.GetTypeOutput没有单个'.' 在他们中.

输出:

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
Run Code Online (Sandbox Code Playgroud)

现在我只需坐下来等待Eric来告诉我我有多错.我接受了我的命运.


Yog*_*gee 5

别名如'int','bool'等不是.NET Framework的一部分.在内部,它们被转换为System.Int32,System.Boolean等.Type.GetType("int")应该返回null.最好的方法是通过使用字典来映射别名与其类型,例如

        Dictionary<string, Type> PrimitiveTypes = new Dictionary<string, Type>();
        PrimitiveTypes.Add("int", typeof(int));
        PrimitiveTypes.Add("long", typeof(long));
        etc.etc..
Run Code Online (Sandbox Code Playgroud)

  • 不需要`GetType("System.Int32")` - `typeof(int)`就行了 (5认同)

Ale*_*ici 5

以下是使用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 + ")");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)