不同场景获取的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
相关产品推荐
相关产品推荐

