如何确定派生类所用泛型接口的类型参数并优化实现?
问题描述
现有大量实现各类接口的属性类,其中部分类实现了ICustomProperty<T>泛型接口。需要找出该接口所有不同的泛型类型参数T。
示例类定义:
AgeProp : ICustomProperty<double> SizeProp : ICustomProperty<string> NameProp : ICustomProperty<string> GradeProp : ICustomProperty<int> DetailProp: ICustomProperty<IDetailValue>
期望结果:包含double、string、int、IDetailValue的类型列表。
现有实现代码如下,但希望获得更优方案:
现有实现代码
public static IEnumerable<Type> GetDistinctGenericTypeArguments<TBase>(IEnumerable<Type> inputTypes) { foreach (var t in inputTypes) { var baseType = t.GetInterfaces() .FirstOrDefault(i => i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(ICustomProperty<>)) ); if (baseType == null) continue; yield return baseType.GenericTypeArguments[0]; } } // 使用示例: var valueTypes = GetDistinctGenericTypeArguments(inputTypes).Distinct().ToList();
需要解决两个核心问题:
- 是否存在比
GetInterfaces().FirstOrDefault(...)更高效的接口查找方式? - 代码中
typeof(ICustomProperty<>)为硬编码,无法通过GetDistinctGenericTypeArguments<ICustomProperty<>>(...)调用(编译器报错:Unexpected use of an unbound generic name),有没有可行的解决办法?
优化方案
1. 更高效的接口查找写法
反射调用GetInterfaces()的开销无法完全避免,但可以通过LINQ链式调用简化代码逻辑,同时减少不必要的中间变量:
public static IEnumerable<Type> GetGenericTypeArguments(IEnumerable<Type> inputTypes) { return inputTypes .SelectMany(type => type.GetInterfaces()) .Where(iface => iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(ICustomProperty<>)) .Select(iface => iface.GenericTypeArguments[0]); }
SelectMany直接展开所有类实现的接口集合,避免循环内重复调用GetInterfaces()- 链式过滤+提取的写法比循环+
FirstOrDefault更简洁,可读性更强 - 若存在类多次实现
ICustomProperty<T>的极端场景,该写法会返回所有匹配的泛型参数,后续通过Distinct()去重即可
2. 解决泛型类型硬编码问题
C#编译器不允许将未绑定的泛型类型(如ICustomProperty<>)作为泛型方法的类型参数传递,因此需要换一种方式传入目标泛型接口的定义:
方案一:通过方法参数传入泛型定义
这是最灵活的方案,完全解耦方法与具体泛型接口:
public static IEnumerable<Type> GetDistinctGenericTypeArguments(IEnumerable<Type> inputTypes, Type genericInterfaceDefinition) { if (!genericInterfaceDefinition.IsGenericTypeDefinition) throw new ArgumentException("参数必须是未绑定的泛型类型定义", nameof(genericInterfaceDefinition)); return inputTypes .SelectMany(type => type.GetInterfaces()) .Where(iface => iface.IsGenericType && iface.GetGenericTypeDefinition() == genericInterfaceDefinition) .Select(iface => iface.GenericTypeArguments[0]) .Distinct(); } // 使用示例: var valueTypes = GetDistinctGenericTypeArguments(inputTypes, typeof(ICustomProperty<>)).ToList();
该方法可以复用在任何需要提取泛型接口参数的场景,只需传入对应的泛型定义类型即可。
方案二:借助泛型约束的折中写法
如果一定要使用泛型方法,可以通过占位符泛型约束间接获取泛型定义,但本质上仍需显式指定泛型接口类型,适用性有限:
public static IEnumerable<Type> GetDistinctGenericTypeArguments<TMarker>(IEnumerable<Type> inputTypes) where TMarker : ICustomProperty<object> // 用object作为占位符,仅用于约束类型 { var targetGenericDefinition = typeof(ICustomProperty<>); return inputTypes .SelectMany(type => type.GetInterfaces()) .Where(iface => iface.IsGenericType && iface.GetGenericTypeDefinition() == targetGenericDefinition) .Select(iface => iface.GenericTypeArguments[0]) .Distinct(); }
这种写法并没有真正消除硬编码,仅为满足泛型方法的语法要求,推荐优先使用方案一。
内容的提问来源于stack exchange,提问作者mike
相关产品推荐
相关产品推荐

