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

我希望得到一个System.Type给定一个string ,该string指定(原始)类型的C#友好名称 ,基本上就像C#编译器在读取C#源代码时所做的那样。

我觉得描述我所追求的是以unit testingforms出现的最佳方式。

我希望存在一种通用技术可以使所有下面的断言通过,而不是试图对特殊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[,][,][][,][][]) ); } 

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

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

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

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

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

 var typeRef = new CodeTypeReference(typeof(int)); 

以下是使用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")); } 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("typeof(" + type + ")"); } } } 

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

以下内容为您提供了所有内置的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(); } } } 

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

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

输出:

 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 

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

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

  Dictionary PrimitiveTypes = new Dictionary(); PrimitiveTypes.Add("int", typeof(int)); PrimitiveTypes.Add("long", typeof(long)); etc.etc.. 

这是一种方法:

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

然后,如果你传入“int”,“int []”等,你会得到相应的类型。

这是我对它的刺痛。 我使用两个类似的库来接近它:

  • Mono C#compiler-as-a-service
  • MS Roslyn C#编译器

我认为它非常干净和简单。

这里我使用的是Mono的C#compiler-as-a-service,即Mono.CSharp.Evaluator类。 (它可以作为Nuget包提供, 不出所料 , 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; } 

接下来:来自“ 41楼的朋友 ”又名Roslyn的对手……

后来:

Roslyn几乎一样容易安装 – 一旦你弄明白什么是什么。 我最终使用了Nuget包“Roslyn.Compilers.CSharp” (或者将其作为VS插件获取)。 请注意,Roslyn 需要 .NET 4.5项目。

代码更清晰:

 using Roslyn.Scripting.CSharp; public static Type GetFriendlyType(string typeName) { ScriptEngine engine = new ScriptEngine(); var type = engine.CreateSession() .Execute(string.Format("typeof({0})", typeName)); return type; }