繁体   English   中英

通过反射从其字符串创建任何类型实例

[英]Create any type instance from its string via reflection

想象以下情况:

用户将代表.NET类型的字符串传递给应用程序,例如stringSystem.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);

obj1string一个实例,但是obj2将失败,因为变量t2null (意味着,给定代码中的第二行无法找到“复杂”类型)。


编辑№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创建通用类型的实例并将其强制转换回该类型?

我(暂时)解决了以下问题:

  1. 检查给定的字符串是否包含<>
  2. 如果是这样,请根据下面提供的函数( ParseGeneric )解析字符串,然后继续使用解析的标记递归
  3. 如果不是,请检查是否出现了数组括号( [][][][,]等)
  4. 使用递归Array::CreateInstance(Type,int[])相应地解析类型
  5. 检查是否存在任何指针'stars'( * ),并使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM