[英]Create any type instance from its string via reflection
想象以下情况:
用户将代表.NET类型的字符串传递给应用程序,例如string
或System.IntPtr
。 假设所讨论的应用程序可以访问在其中定义了给定类型的程序集,则可以基于字符串创建给定类型的实例。
我已经设法创建了这样的应用程序; 问题仅仅是,我还不能创建“复杂”或“嵌套”类型,例如:
System.Tuple<string, System.Action>
类的泛型 T
数组,例如int[]
, System.IntPtr[]
等。 T
指针,例如int*
, char**
, Namespace.MyStruct*
等。 我的问题是:仅给出类型的字符串表示形式(当然还有所有必需的程序集)时,如何创建此类嵌套类型实例?
.NET BCL是否包含某种string --> Type
-parser? 还是我必须使用某种形式的递归regex-parser和Activator.CreateInstance
?
编辑№1:
由于这个问题似乎太广泛了,我将尝试澄清一下自己:
我能够为“简单”类型创建类型实例-但是,我正在努力创建“复杂”类型的类型实例,例如:
Type t1 = typeof(string).Assembly.GetType("System.String");
Type t2 = typeof(string).Assembly.GetType("System.Tuple<System.String, System.Int32>");
object obj1 = Activator.CreateInstance(t1);
object obj2 = Activator.CreateInstance(t2);
obj1
是string
一个实例,但是obj2
将失败,因为变量t2
为null
(意味着,给定代码中的第二行无法找到“复杂”类型)。
编辑№2:
Type::MakeGenericType(Type[])
的使用显然很有帮助,但是创建这种类型的实例的最简单/最快(?)方式将是怎样的:
IEnumerable<Tuple<int[,], char[][], Dictionary<string, Func<int, int*, byte>>>>
我将不得不编写某种基于正则表达式的解析器,该解析器在给定字符串的不同部分上进行递归迭代。
编辑№3:
我发现了System::CodeDom::CodeTypeReference
并且我目前正在寻找一种基于给定CodeTypeReference
-instance(可以使用类型的字符串表示形式创建)来获取类型的方法。
编辑№4:( 对不起所有编辑)
我想我在这篇SO帖子中找到了解决方案。
我可能会丢失一些东西,但是看起来您在寻找Reflection 。 具体来说,就是GetType
方法。 文档指出有关此方法的以下内容:
获取具有指定名称的Type,执行区分大小写的搜索。
然后,您将要查看Activator.CreateInstance
:
使用该类型的默认构造函数创建指定类型的实例
但是,在为泛型类型创建实例之前,您将需要查看`Type.MakeGenericType' :
将类型数组的元素替换为当前泛型类型定义的类型参数,并返回表示所得构造类型的Type对象。
您可能还会发现其他问题的答案也很有用: 如何使用Activator创建通用类型的实例并将其强制转换回该类型?
我(暂时)解决了以下问题:
<
或>
ParseGeneric
)解析字符串,然后继续使用解析的标记递归 []
, [][]
, [,]
等) Array::CreateInstance(Type,int[])
相应地解析类型 *
),并使用Marshal::StructureToPtr
相应地解析类型。 ParseGeneric
方法:
public static Type FetchGenericType(string typestring) { Match m; if ((m = Regex.Match(typestring, )).Success) { string cls = m.Groups["class"].ToString(); string par = m.Groups["params"].Success ? m.Groups["params"].ToString() : ""; List<string> paramtypes = new List<string>(); int s = 0, e = 0; for (int i = 0, c = 0, l = par.Length; i < l; i++) switch (par[i]) { case ',': if (c > 0) goto default; paramtypes.Add(par.Substring(s, e)); s = i + 1; e = 0; break; case '<': ++c; goto default; case '>': --c; goto default; default: ++e; break; } // I know, that this is bad as hell, but what should I do instead? paramtypes.Add(par.Substring(s, e)); IEnumerable<Type> @params = from type in paramtypes where !string.IsNullOrWhiteSpace(type) select FetchGenericType(type); string paramstring = string.Join(", ", from type in @params select "[" + type.FullName + ", " + type.Assembly.GetName().Name + "]"); string result = @params.Count() == 0 ? cls : string.Format("{0}`{1}[{2}]", cls, @paramsCount(), paramstr); // The string has now the format '...List`1[[System.String, mscorlib]]' // or: 'System.Tuple[[System.Int32, mscorlib], [System.Object, mscorlib]]' ... return FetchType(result); } else return FetchType(typestring); }
函数FetchType
执行一些基本的数组括号解析,然后通过查看给定的程序集,基于结果字符串获取类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.