想象一下以下场景:
用户将字符串传递给应用程序,该应用程序代表.NET类型,例如string
或System.IntPtr
。假设有问题的应用程序可以访问定义了给定类型的程序集,它可以根据字符串创建给定类型的实例。
我设法创建了这样一个应用程序;问题是,我还没有(还)能够创建“复杂”或“嵌套”类型,例如:
System.Tuple<string, System.Action>
T
的数组int[]
,System.IntPtr[]
等...... T
的指针,如int*
,char**
,Namespace.MyStruct*
等...... 我的问题是:如果只给出了类型的字符串表示(当然还有所有必需的程序集),我怎样才能创建这样的嵌套类型实例?
.NET BCL是否包含某种string --> Type
- 解析器?或者我是否必须使用某种形式的递归正则表达式解析器和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
- 实例的类型(可以使用类型的字符串表示创建)。
编辑№4: (抱歉所有修改)
我想我在this SO post找到了我的解决方案。
答案 0 :(得分:2)
我可能会遗漏一些东西,但看起来你正在寻找Reflection。具体来说,GetType
方法。该文档说明了以下有关此方法的内容:
获取具有指定名称的Type,执行区分大小写的搜索。
然后你会想看看Activator.CreateInstance
:
使用该类型的默认构造函数
创建指定类型的实例
在为通用类型创建实例之前,您需要查看`Type.MakeGenericType':
为当前泛型类型定义的类型参数替换类型数组的元素,并返回表示结果构造类型的Type对象。
您可能会发现其他问题的答案也很有用:How to use Activator to create an instance of a generic Type and casting it back to that type?
答案 1 :(得分:1)
我解决了(暂时)如下:
<
或>
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
执行一些基本的数组括号解析,然后通过查看给定的程序集,根据结果字符串获取类型。