超越属性和反射的奇怪效应

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以下消息:

找不到属性集方法.

这是预期的吗?因为我似乎没有找到一个方法的组合,BindingFlagsGetProperty()方法返回属性与反射中的工作get/set对.

编辑:如果我使用BindingFlags.DeclaredOnlyon ,我会期望这种行为,GetProperties()但默认(BindingFlags.Default)将继承的成员考虑在内,而且TestString的setter显然是继承的!

Ani*_*Ani 6

这是一个解决方法:

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#中)向重写属性添加新访问器,因此此"原始"类型的属性声明应包含所有相关的访问器.

  • 我不太明白这一点,这不是一种迂回的说法`typeof(A).GetProperty("TestString")`或`typeof(B).BaseType.GetProperty("TestString")`? (2认同)