超越属性和reflection的奇怪效应

我在.NET / Reflection中遇到了一个奇怪的行为,无法找到任何解决方案/解释:

class A { public virtual string TestString { get; set; } } class B : A { public override string TestString { get { return "x"; } } } 

由于属性只是函数对( get_PropName()set_PropName() get_PropName()set_PropName()只覆盖“get”部分应该保留“set”部分,就像它在基类中一样。 这就是如果您尝试实例化B类并为TestString赋值,它会使用A类的实现。

但是如果我在reflection中查看B类的实例化对象会发生什么呢?

 PropertyInfo propInfo = b.GetType().GetProperty("TestString"); propInfo.CanRead ---> true propInfo.CanWrite ---> false(!) 

如果我尝试从reflection中调用setter:

 propInfo.SetValue("test", b, null); 

我甚至会得到一个带有以下消息的ArgumentException

找不到属性集方法。

这是预期的吗? 因为我似乎没有为GetProperty()方法找到BindingFlags的组合,该方法返回带有来自reflection的工作get / set对的属性。

编辑:如果我在GetProperties()上使用BindingFlags.DeclaredOnly ,我会期望这种行为,但默认( BindingFlags.Default )将inheritance的成员考虑在内,并且显然inheritance了TestString的setter!

这是一个解决方法:

 typeof(B).GetProperty("TestString") .GetAccessors() // { B.get_TestString() } .First() // B.get_TestString() .GetBaseDefinition() // A.get_TestString() .DeclaringType // typeof(A) .GetProperty("TestString") // A.TestString: CanRead and CanWrite 

这种方法应该相当稳健。 如果您正在寻找非公共访问者,则需要更加小心(BindingFlags)。

编辑:

请注意,此方法不同于“硬编码”类型typeof(A).GetProperty("TestString")typeof(B).BaseType.GetProperty("TestString")因为它找到声明所讨论属性的实际原始类型。 由于派生类型无法(至少在C#中)向重写属性添加新访问器,因此此“原始”类型的属性声明应包含所有相关访问器。

你没有覆盖一个方法,你正在覆盖一个属性定义

该属性的默认定义包括Get / Set方法,并且您的新定义仅包含Get方法,因此您的覆盖属性仅具有Get available,而不是Set

编辑

如果你运行像Reflector这样的东西,你会看到

 class A { public virtual string TestString { get; set; } } class B : A { public override string TestString { get { return "x"; } } } 

编译成类似的东西

 internal class A { // Fields [CompilerGenerated] private string k__BackingField; // Methods public A(); // Properties public virtual string TestString { [CompilerGenerated] get; [CompilerGenerated] set; } } internal class B : A { // Methods public B(); // Properties public override string TestString { get; } } 

在代码中设置值时,实际上是在调用类似B.base.set_TestValue 。 当您反映某些内容时,您正在尝试查找不存在的B.set_TestValue

虽然您无法覆盖属性,但您可以覆盖属性定义(假设它不与基本属性定义冲突)。 由于你的问题最初是用WPF标记的,所以我当时想的是DependencyProperties,它实际上是属性定义,而不是你可能想到的意义上的属性。