You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为开放泛型类型的属性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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:23:50