求助:通过反射调用HashSet.ExceptWith()方法失败,如何解决?
反射调用HashSet.ExceptWith()方法失败的解决办法
我尝试通过反射调用HashSet.ExceptWith()方法,但一直无法成功。我没法创建泛型方法,因为这个方法本身似乎不是泛型方法;同时直接用Invoke调用也报错。请问该怎么实现?
附上我的代码:
var newSet = pi.GetValue(newItem); var existingSet = pi.GetValue(existingItem); MethodInfo methodExcept = typeof(HashSet<>).GetMethod("ExceptWith"); // 这行抛出异常:Void ExceptWith(System.Collections.Generic.IEnumerable`1[T]) is not a GenericMethodDefinition. // MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.' MethodInfo genericExcept = methodExcept.MakeGenericMethod(pi.GetType().GetGenericTypeDefinition().UnderlyingSystemType); // 这行抛出异常 'Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.' methodIntersect.Invoke(existingSet, new[] { newSet }); // 这行无法执行,因为变量实例化失败 genericIntersect.Invoke(existingSet, new[] { newSet });
问题根源
你的代码有两个核心错误:
- 直接操作
HashSet<>这个泛型类型定义的方法,此时方法仍包含未绑定的泛型参数T,无法直接调用; - 获取泛型参数的逻辑错误,应该从
existingSet的实际类型中提取已绑定的泛型参数,而非从pi的类型中获取。
两种正确实现方式
方式一:从实例的闭合类型直接获取方法
existingSet的实际类型是已经绑定了具体泛型参数的HashSet<T>(比如HashSet<int>),直接从这个类型里拿方法就能调用:
var newSet = pi.GetValue(newItem); var existingSet = pi.GetValue(existingItem); // 获取实例的实际类型(已绑定泛型参数) Type concreteSetType = existingSet.GetType(); // 获取泛型参数T Type elementType = concreteSetType.GetGenericArguments()[0]; // 构造ExceptWith的参数类型IEnumerable<T> Type enumerableType = typeof(IEnumerable<>).MakeGenericType(elementType); // 获取闭合的ExceptWith方法 MethodInfo exceptMethod = concreteSetType.GetMethod("ExceptWith", new[] { enumerableType }); // 执行方法 exceptMethod.Invoke(existingSet, new[] { newSet });
方式二:从泛型定义构造闭合方法
如果一定要从HashSet<>泛型定义出发,需要先绑定具体的泛型参数再获取可调用的方法:
var newSet = pi.GetValue(newItem); var existingSet = pi.GetValue(existingItem); Type concreteSetType = existingSet.GetType(); Type elementType = concreteSetType.GetGenericArguments()[0]; // 从HashSet<>泛型定义获取方法定义 MethodInfo exceptMethodDef = typeof(HashSet<>).GetMethod("ExceptWith"); // 绑定泛型参数得到可调用的闭合方法 MethodInfo exceptMethod = exceptMethodDef.MakeGenericMethod(elementType); // 执行方法 exceptMethod.Invoke(existingSet, new[] { newSet });
关键注意点
HashSet<>是泛型类型定义,它的ExceptWith方法依赖未绑定的T,必须绑定具体类型后,方法的ContainsGenericParameters才会变为false,才能安全调用;- 确保传入
Invoke的参数类型与方法要求匹配,这里newSet必须是IEnumerable<T>类型(它本身是HashSet<T>的话也符合要求,因为HashSet实现了IEnumerable)。
内容的提问来源于stack exchange,提问作者njun
相关产品推荐
相关产品推荐

