在我项目的某个地方,我需要创建一个具体的泛型类型,将泛型类型定义(带有一个参数)和一个参数类型作为参数。
为此,我编写了一个非常简单的方法:
to_f
但是,在某些时候,我需要创建一个类型,比如Type MakeGenericType(Type definition, Type parameter)
{
return definition.MakeGenericType(parameter);
}
,其中给定的元素类型为List<List<T>>
。虽然我可以使用my方法创建类型T
,但后续尝试从中创建具体类型List<List<T>>
失败 - 请参阅下面的代码:
List<List<int>>
未处理的类型&#39; System.InvalidOperationException&#39; 发生在mscorlib.dll
其他信息: System.Collections.Generic.List`1 [System.Collections.Generic.List`1 [T]] 不是GenericTypeDefinition。 MakeGenericType只能被调用 Type.IsGenericTypeDefinition为true的类型。
此外,以下电话甚至无法编译:
var genericList = MakeGenericType(typeof(List<>), typeof(List<>)); // success
MakeGenericType(genericList, typeof(int)); // exception
我已经MakeGenericType(typeof(List<List<>>), typeof(int));
检查了IsGenericTypeDefinition
和ContainsGenericParameters
之间的区别。但是,我仍然没有想法,如何处理像genericList
这样的类型对象。
显然,使用反射我可以构造一个类型对象,这与它无关 - 这对我来说非常混乱。
所以问题是,如何从泛型创建具体类型,其中包含泛型类型定义作为参数?它有可能吗?
答案 0 :(得分:4)
您需要将传递的类型分解为泛型类型定义,并使用以下内容构建生成的泛型类型:
static Type MakeGenericType(Type definition, Type parameter)
{
var definitionStack = new Stack<Type>();
var type = definition;
while (!type.IsGenericTypeDefinition)
{
definitionStack.Push(type.GetGenericTypeDefinition());
type = type.GetGenericArguments()[0];
}
type = type.MakeGenericType(parameter);
while (definitionStack.Count > 0)
type = definitionStack.Pop().MakeGenericType(type);
return type;
}
答案 1 :(得分:1)
type参数本身就是一个泛型类型,所以只需要编写匹配的函数:
// List<List<int>>
MakeGenericType(
typeof(List<>),
MakeGenericType(
typeof(List<>),
typeof(int)
)
);
答案 2 :(得分:1)
除Ivan Stoev的答案外,这里还有MakeGenericType
的{{1}}版本,可以生成和处理部分定义的&#34;泛型类型:
Type MakeGenericType(Type type, Type parameter)
{
if (!type.ContainsGenericParameters)
throw new ArgumentException(nameof(type));
bool replaced = false;
return MakeGenericType(type, parameter, ref replaced);
}
Type MakeGenericType(Type type, Type parameter, ref bool replaced)
{
if (type.IsGenericParameter)
if (replaced)
return type;
else
{
replaced = true;
return parameter;
}
if (type.IsGenericTypeDefinition)
{
var parameters = type.GetTypeInfo().GenericTypeParameters.ToArray();
parameters[0] = parameter;
replaced = true;
return type.MakeGenericType(parameters);
}
if (type.IsGenericType && type.ContainsGenericParameters)
{
var parameters = type.GenericTypeArguments.ToArray();
for (int i = 0; i < parameters.Length; i++)
parameters[i] = MakeGenericType(parameters[i], parameter, ref replaced);
return type
.GetGenericTypeDefinition()
.MakeGenericType(parameters);
}
return type;
}
以下来电成功:
var d0 = MakeGenericType(typeof(Dictionary<,>), typeof(Tuple<,>)); // Dictionary`2[Tuple`2[T1,T2],TValue]
var d1 = MakeGenericType(d0, typeof(double)); // Dictionary`2[Tuple`2[Double,T2],TValue]
var d2 = MakeGenericType(d1, typeof(float)); // Dictionary`2[Tuple`2[Double,Single],TValue]
var d3 = MakeGenericType(d2, typeof(Func<,,>)); // Dictionary`2[Tuple`2[Double,Single],Func`3[T1,T2,TResult]]
var d4 = MakeGenericType(d3, typeof(short)); // Dictionary`2[Tuple`2[Double,Single],Func`3[Int16,T2,TResult]]
var d5 = MakeGenericType(d4, typeof(object)); // Dictionary`2[Tuple`2[Double,Single],Func`3[Int16,Object,TResult]]
var d6 = MakeGenericType(d5, typeof(int)); // Dictionary`2[Tuple`2[Double,Single],Func`3[Int16,Object,Int32]]