naa*_*cal 13 .net c# reflection overriding properties
我在.NET/Reflection中遇到了一个奇怪的行为,无法找到任何解决方案/解释:
class A
{
public virtual string TestString { get; set; }
}
class B : A
{
public override string TestString
{
get { return "x"; }
}
}
Run Code Online (Sandbox Code Playgroud)
由于属性只是函数对(get_PropName()
,set_PropName()
),只覆盖"get"部分应该保留"set"部分,就像它在基类中一样.这就是如果您尝试将类B实例化并赋值TestString
,它会使用A类的实现.
但是如果我在反射中查看B类的实例化对象会发生什么呢?
PropertyInfo propInfo = b.GetType().GetProperty("TestString");
propInfo.CanRead ---> true
propInfo.CanWrite ---> false(!)
Run Code Online (Sandbox Code Playgroud)
如果我尝试从反射中调用setter:
propInfo.SetValue("test", b, null);
Run Code Online (Sandbox Code Playgroud)
我甚至会收到ArgumentException
以下消息:
找不到属性集方法.
这是预期的吗?因为我似乎没有找到一个方法的组合,BindingFlags
该GetProperty()
方法返回属性与反射中的工作get/set对.
编辑:如果我使用BindingFlags.DeclaredOnly
on ,我会期望这种行为,GetProperties()
但默认(BindingFlags.Default
)将继承的成员考虑在内,而且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
Run Code Online (Sandbox Code Playgroud)
这种方法应该相当稳健.如果您正在寻找非公共访问者,则需要更加小心(BindingFlags).
编辑:
请注意,此方法与"硬编码"不同,typeof(A).GetProperty("TestString")
或者typeof(B).BaseType.GetProperty("TestString")
因为它找到了声明所讨论属性的实际原始类型.由于派生类型无法(至少在C#中)向重写属性添加新访问器,因此此"原始"类型的属性声明应包含所有相关的访问器.