【问题标题】:Create any type instance from its string via reflection通过反射从其字符串创建任何类型实例
【发布时间】:2016-09-14 02:32:41
【问题描述】:

想象以下场景:

用户将字符串传递给应用程序,该字符串表示 .NET-Type,例如stringSystem.IntPtr。假设有问题的应用程序可以访问定义给定类型的程序集,它可以根据字符串创建给定类型的实例。

我已经设法创建了这样一个应用程序;问题只是,我(还)不能创建 "complex""nested" 类型,例如:

  • System.Tuple<string, System.Action>这样的泛型
  • T 的数组,例如 int[]System.IntPtr[] 等...
  • T 的指针,如int*char**Namespace.MyStruct* 等...
  • 上述情况的任何(可能)组合

我的问题是:如果只给出类型的字符串表示形式(当然还有所有必需的程序集),我该如何创建这样的嵌套类型实例?

.NET BCL 是否包含某种string --> Type-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&lt;Tuple&lt;int[,], char[][], Dictionary&lt;string, Func&lt;int, int*, byte&gt;&gt;&gt;&gt;
我将不得不编写某种基于正则表达式的解析器,它递归地遍历给定字符串的不同部分......


编辑№3:
我发现了System::CodeDom::CodeTypeReference,我目前正在寻找一种方法来根据给定的CodeTypeReference-instance(可以使用类型的字符串表示形式创建)获取类型。


编辑№4: (抱歉所有的编辑)
我想我在this SO post 找到了我的解决方案。

【问题讨论】:

  • 我没有投票结束这个问题,因为虽然可能有很多方法可以做到这一点(所以它太宽泛了)也有内置的 BCL 方法可以非常标准地做到这一点,所以我认为对 SO 提出问题实际上是有益的。
  • @Jeff:我编辑了我的问题....你认为这样可以吗?如果没有,我应该如何编辑它以更好地匹配 SO 的指南? :)
  • 好吧,正如我所说,我认为这个问题还可以。话虽如此,请随意回答您自己的问题,因为您似乎找到了更好的解决方案
  • @Jeff:我还不打算回答我的问题(我可能会在几天后),因为我想让其他用户有机会回答......而且因为我有发现我当前的解决方案存在一些问题:)
  • 泛型类型的语言不规则。如果您有兴趣,请查找上下文相关和上下文无关的语言,我在这里解释太多了,抱歉

标签: c# string reflection casting


【解决方案1】:

我可能遗漏了一些东西,但您似乎正在寻找 Reflection。具体来说,GetType 方法。该文档说明了有关此方法的以下内容:

获取具有指定名称的类型,执行区分大小写的搜索。

那你会想看Activator.CreateInstance

使用该类型的默认构造函数创建指定类型的实例

不过,在为泛型类型创建实例之前,您可能需要查看`Type.MakeGenericType'

将类型数组的元素替换为当前泛型类型定义的类型参数,并返回一个表示生成的构造类型的 Type 对象。

您可能会发现其他问题的答案也很有用:How to use Activator to create an instance of a generic Type and casting it back to that type?

【讨论】:

    【解决方案2】:

    我(暂时)解决了如下:

    1. 检查给定字符串是否包含&lt;&gt;
    2. 如果是这样,请根据下面给出的函数 (ParseGeneric) 解析字符串并继续递归地使用解析后的标记
    3. 如果没有,请检查是否出现任何数组括号([][][][,] 等)
    4. 使用递归Array::CreateInstance(Type,int[]) 相应地解析类型
    5. 检查指针“星”(*) 的任何出现并使用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 进行一些基本的数组括号解析,然后通过查看给定的程序集根据结果字符串获取类型。

    【讨论】:

      猜你喜欢
      • 2014-06-04
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2015-07-22
      相关资源
      最近更新 更多