哪些条件下获取同一属性的PropertyInfo会是不同实例而非缓存值?
何时代表同一属性的两个PropertyInfo引用会不是同一实例?
通常两次获取某类属性的PropertyInfo时会返回同一实例:
var propertyOne = typeof(Foo).GetProperty(nameof(Foo.Bar)); var propertyTwo = typeof(Foo).GetProperty(nameof(Foo.Bar)); Console.WriteLine(propertyOne == propertyTwo); // 输出 "True"
这是因为.NET内部会缓存PropertyInfo实例,第二次调用GetProperty(...)时直接返回缓存的实例,但这种引用相等并非绝对保证。
我曾在VS调试时遇到过特殊场景:代表同一具体类同一属性的两个PropertyInfo实例,调用Equals(...)结果不相等。检查后发现它们的属性名、类型、反射相关属性等都完全一致,但确实是不同实例——其中一个实例是从LambdaExpression的主体获取的。之后我无法复现该问题,无论用何种方式获取都得到同一实例,也没有相关日志记录。我打算不再依赖引用相等比较,但好奇这种情况的发生条件及复现方法。
会返回不同PropertyInfo实例的场景
- 动态生成类型的属性:使用Reflection.Emit或其他动态代码生成技术创建的类型,即使属性定义和原类型完全一致,其PropertyInfo实例也会和原类型对应属性的实例不同。多次生成结构相同的动态类型,各自的PropertyInfo实例也互不相同。
- 跨应用程序域获取:在.NET Framework中,不同AppDomain的类型是隔离的。同一程序集里的同一类,在不同AppDomain中获取的PropertyInfo是不同引用——每个AppDomain都有独立的类型缓存和反射对象实例。
- Lambda表达式解析的特殊情况:你遇到的LambdaExpression场景可能和表达式树的构造或编译逻辑有关。比如动态构建的表达式树(而非直接从编译后代码提取),在某些.NET版本或优化逻辑下可能生成新的PropertyInfo实例。这种场景很难稳定复现,具体取决于表达式树的构建方式和运行时环境。
- 程序集重复加载:同一程序集通过不同加载上下文多次加载到同一AppDomain(比如用
Assembly.LoadFrom加载本地文件,同时该程序集也在GAC中),此时同一类的类型实例本身就是不同的,对应的PropertyInfo自然也不是同一引用。 - 特殊绑定标志组合:虽然少见,但如果两次获取属性时使用了差异较大的
BindingFlags组合(比如一次仅指定BindingFlags.Public,另一次同时指定BindingFlags.Public | BindingFlags.DeclaredOnly),在某些边缘场景下可能返回不同的PropertyInfo实例。不过大多数情况下,只要指向同一属性,即使绑定标志不同,.NET仍会返回缓存实例。
最佳实践
永远不要依赖PropertyInfo的引用相等判断是否指向同一属性,正确的做法是:
- 使用
PropertyInfo.Equals()方法(该方法会验证属性所属类型及成员标识是否一致) - 或者组合比较
PropertyInfo.MetadataToken和DeclaringType,确保成员和所属类型都匹配
内容的提问来源于stack exchange,提问作者Ergwun
相关产品推荐
相关产品推荐

