C#泛型类型T转换为List<>实现列表相等性校验问题求助
问题根源
你标注的运行时异常由错误的API调用导致:x本身就是List<U>类型的实例,x.GetType()已经是构造完成的封闭泛型类型(如List<int>),MakeGenericType方法仅适用于开放泛型定义(如typeof(List<>))传入参数生成封闭泛型类型,对已构造的泛型类型调用该方法会直接抛出异常。
你的核心需求是编译期未知列表元素类型的情况下调用SequenceEqual,可以通过以下两种方案实现:
方案1:dynamic 运行时重载解析(推荐)
利用C# dynamic的运行时方法重载解析能力,自动匹配对应元素类型的SequenceEqual泛型重载,代码极简且性能优于反射方案(dynamic的解析结果会被缓存,后续调用开销极低):
public bool Compare<T>(T x, T y) { // 前置空值判断 if (ReferenceEquals(x, null) && ReferenceEquals(y, null)) return true; if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false; if (typeof(T).IsSubClassOfGenericBaseType(typeof(List<>))) { // 转dynamic后运行时自动匹配正确的SequenceEqual泛型重载 return Enumerable.SequenceEqual((dynamic)x, (dynamic)y); } return EqualityComparer<T>.Default.Equals(x, y); }
注意:dynamic依赖JIT运行时泛型解析,在AOT编译环境(如Unity IL2CPP、.NET Native)下可能会抛出异常,这类场景请使用方案2
方案2:反射调用泛型方法
手动构造对应元素类型的SequenceEqual泛型方法并反射调用,兼容性更好,适合AOT等无法使用dynamic的场景:
public bool Compare<T>(T x, T y) { // 前置空值判断 if (ReferenceEquals(x, null) && ReferenceEquals(y, null)) return true; if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false; if (typeof(T).IsSubClassOfGenericBaseType(typeof(List<>))) { Type elementType = typeof(T).GetGenericArguments().Single(); // 获取SequenceEqual开放泛型方法(两个参数的重载) var sequenceEqualOpenMethod = typeof(Enumerable) .GetMethods() .First(m => m.Name == nameof(Enumerable.SequenceEqual) && m.GetParameters().Length == 2); // 构造对应元素类型的封闭泛型方法 var closedMethod = sequenceEqualOpenMethod.MakeGenericMethod(elementType); // 调用方法返回结果 return (bool)closedMethod.Invoke(null, new object[] { x, y }); } return EqualityComparer<T>.Default.Equals(x, y); }
内容的提问来源于stack exchange,提问作者Francois Louw
相关产品推荐
相关产品推荐

