超越属性和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,它实际上是属性定义,而不是你可能想到的意义上的属性。