将类型参数传递给没有约束的泛型类型会引发约束异常

本文关键字:约束 泛型类型 异常 参数传递 类型 | 更新日期: 2023-09-27 18:20:31

考虑以下代码:

IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof(object))
                                      .GetTypes()
                                      .Where(t => t.IsGenericType)
                                      .Where(t => t.GetGenericArguments().Length == 1)
                                      .Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0);

oneParameterTypes应该包含System.dll程序集中的所有泛型类型,可以向其传递单个泛型类型参数,并且不对其应用约束。

现在,让我们传入一个类型参数:

IEnumerable<Type> intParameterTypes = oneParameterTypes.Select(t => t.MakeGenericType(typeof(int)))
                                                       .ToList();

这应该行得通,对吧?我的意思是,oneParameterTypes中的所有类型都不应该有类型约束,所以System.Int32应该是一个有效的类型。

然而,这条线抛出了以下异常:

"System.RuntimeType+ListBuilder"1[T]"上的GenericArguments[0],"System.Int32"违反了类型为"T"的约束。

这个ListBuilder'1类型是什么?如果它有类型约束,为什么它在oneParameterTypes中?为什么我的Where过滤器不工作?

将类型参数传递给没有约束的泛型类型会引发约束异常

我认为Chris是对的。

这样试试:

IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof (object))
    .GetTypes()
    .Where(t => t.IsGenericType)
    .Where(t => t.GetGenericArguments().Length == 1)
    .Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0 &&
                !genericArgument.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint);
    });

文档并没有真正清楚Type.GetGenericParameterConstraints实际寻找的内容:

使用IsClass属性来确定约束是否为基类约束;如果属性返回false,则该约束为接口约束如果类型参数没有类约束和接口约束,则返回一个空数组

您可以隐含地理解,它只会检查基类或接口约束。为了获得存在约束的完整情况,您需要对GenericParameterAttributes进行额外检查。您可以使用HasFlag或位掩码:

IEnumerable<Type> oneParameterTypes = Assembly.GetAssembly(typeof(object))
              .GetTypes()
              .Where(t => t.IsGenericType)
              .Where(t => t.GetGenericArguments().Length == 1)
              .Where(t => t.GetGenericArguments().Single().GetGenericParameterConstraints().Length == 0 && !t.GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint);

typeof()或.GetType()方法不返回实际的类,而是返回类型对象表示,这将帮助我们将类型名称用作字符串。

相反,您可以使用反射类,找到该类型的类,并将其用作参数