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

不同场景获取的PropertyInfo差异原因及修改方法安全性验证

关于PropertyInfo Equality与ExpressionHelper的疑问解答

类型定义

public abstract class Entity<TId>
{
   public TId Id { get; set; }
}

public class Country : Entity<int>
{}
public class Language: Entity<int>
{}

原ExpressionHelper实现

internal static class ExpressionHelper
{
   public static PropertyInfo HasKey<TEntityType, TKey>(Expression<Func<TEntityType, TKey>> keyDefinitionExpression)
   {
      LambdaExpression lambda = keyDefinitionExpression;
      MemberExpression member = (MemberExpression)lambda.Body;
      return member.Member as PropertyInfo;
   }
}

技术疑问与解答

1. GetProperty获取的Country.Id和Language.Id为什么不相等?

当通过typeof(Country).GetProperty("Id")获取属性信息时,CLR返回的是关联到Country类型的PropertyInfo实例,其ReflectedType属性值为Country;同理,typeof(Language).GetProperty("Id")返回的PropertyInfo实例的ReflectedType是Language。

虽然这两个PropertyInfo指向的是基类Entity<int>中定义的同一个Id属性,但PropertyInfo.Equals方法会比较ReflectedType等元数据信息,因此两个实例判定为不相等。

2. ExpressionHelper.HasKey获取的两个Id属性为什么相等,且和GetProperty的结果不等?

在表达式树c => c.Id中,由于子类Country和Language都没有重写或隐藏基类的Id属性,编译器生成的MemberExpression直接指向基类Entity<int>上的Id属性。因此,无论泛型参数是Country还是Language,HasKey方法返回的都是基类属性对应的PropertyInfo实例,其ReflectedType为Entity<int>,所以两个实例相等。

而GetProperty返回的是子类反射得到的PropertyInfo(ReflectedType为子类),与基类的PropertyInfo实例元数据不同,因此两者不相等。

3. 更新后的HasKey实现是否安全?

这个实现是安全的,且能对齐GetProperty的行为,同时处理了子类隐藏基类属性的场景:

  • 若子类未隐藏基类的Id属性,代码会通过callingType.GetProperty(pInfo.Name)获取关联到子类的PropertyInfo实例,确保返回结果的ReflectedType与泛型参数TEntityType一致;
  • 若子类**隐藏(new)**了基类的Id属性,此时表达式树的MemberExpression会直接指向子类的属性,pInfo.ReflectedType等于callingType,直接返回子类的PropertyInfo,逻辑正确;
  • 唯一需要注意的边界场景:如果子类存在同名但不同类型的属性,但由于泛型约束了TKey与属性类型一致,这种情况在当前代码结构下不会发生。

内容的提问来源于stack exchange,提问作者Sam Xu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:34:59