如何为开放泛型类型的属性Getter创建可调用委托?
解决方案:基于开放泛型PropertyInfo创建强类型Getter委托
当然可以做到!你不用每次针对具体泛型类型重复查找属性——只需要在开放泛型接口ITest<>上查找一次Item属性,之后就能通过表达式树或反射绑定的方式,为任意具体的ITest<T>生成对应的Func<ITest<T>, T>委托。
为什么你的初始尝试失败?
你遇到的问题核心是:typeof(ITest<>).GetProperty("Item").GetMethod是开放泛型类型的成员方法,而非泛型方法本身。MakeGenericMethod仅适用于自身带有泛型参数的方法(比如void Foo<T>()),而这个GetMethod属于泛型类型,但方法本身没有泛型参数,所以无法直接调用MakeGenericMethod来实例化它。
可行方案:用表达式树构建委托
表达式树是最直观且高效的方式,它能自动将开放泛型属性绑定到具体的闭合泛型类型上,无需重复调用GetProperty。下面是CreateGetter方法的实现:
using System.Linq.Expressions; // 可选:添加缓存提升重复调用性能 private static readonly Dictionary<(Type ClosedInterfaceType, PropertyInfo OpenPropertyInfo), Delegate> _getterCache = new(); public static Func<TInterface, TProperty> CreateGetter<TInterface, TProperty>(PropertyInfo openPropertyInfo) { var cacheKey = (typeof(TInterface), openPropertyInfo); // 先检查缓存,避免重复编译 if (_getterCache.TryGetValue(cacheKey, out var cachedDelegate)) return (Func<TInterface, TProperty>)cachedDelegate; // 验证传入的属性是否来自正确的开放泛型类型 if (!openPropertyInfo.DeclaringType.IsGenericTypeDefinition) throw new ArgumentException("Property must belong to an open generic type definition"); var closedType = typeof(TInterface); if (!closedType.IsGenericType || closedType.GetGenericTypeDefinition() != openPropertyInfo.DeclaringType) throw new ArgumentException("Closed interface type does not match the property's declaring open generic type"); // 构建表达式:参数为ITest<T>实例,访问其Item属性 var instanceParam = Expression.Parameter(closedType, "instance"); var propertyAccessExpr = Expression.Property(instanceParam, openPropertyInfo); // 编译为强类型委托 var getter = Expression.Lambda<Func<TInterface, TProperty>>(propertyAccessExpr, instanceParam).Compile(); // 存入缓存 _getterCache[cacheKey] = getter; return getter; }
测试方法调用示例
你的TestMethod可以这样修改后通过测试:
public void TestMethod<T>(ITest<T> x) { var propertyInfo = typeof(ITest<>).GetProperty("Item"); // 传入具体的泛型接口类型和属性类型 var getter = CreateGetter<ITest<T>, T>(propertyInfo); Assert.IsTrue(getter(x).Equals(x.Item)); }
为什么这个方案有效?
表达式树的Expression.Property方法会自动处理开放泛型属性到闭合泛型类型的绑定:当你传入开放泛型的PropertyInfo和闭合泛型类型的参数表达式时,它会解析出该闭合类型上对应的具体属性访问方法,无需你手动再次查找属性。
性能优化说明
添加缓存字典后,同一个闭合类型的CreateGetter调用只会编译一次表达式树,后续调用直接返回缓存的委托,性能几乎等同于直接调用属性 getter。
内容的提问来源于stack exchange,提问作者Philip C
相关产品推荐
相关产品推荐

