[英]Convert “C# friendly type” name to actual type: “int” => typeof(int)
我希望得到一个System.Type
给定一个string
,该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[,][,][][,][][]) );
}
到目前为止我尝试了什么:
这个问题是我的一个老问题的补充,询问如何从一个类型获得“友好名称”。
这个问题的答案是:使用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));
你有没有大部分已经解决了吗?
以下内容为您提供了所有内置的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();
}
}
}
这基于几个假设,我认为在撰写本文时这些假设是正确的:
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<string, Type> PrimitiveTypes = new Dictionary<string, Type>();
PrimitiveTypes.Add("int", typeof(int));
PrimitiveTypes.Add("long", typeof(long));
etc.etc..
以下是使用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 + ")");
}
}
}
这是一种方法:
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,即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<Type>(string.Format("typeof({0})", typeName));
return type;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.