具有覆盖属性和反射的奇怪效果 [英] Strange Effect with Overridden Properties and Reflection

查看:82
本文介绍了具有覆盖属性和反射的奇怪效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've come across a strange behaviour in .NET/Reflection and cannot find any solution/explanation for this:

class A 
{
   public virtual string TestString { get; set; }
}

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

由于属性只是功能对(get_PropName()set_PropName())的对,因此仅覆盖"get"部分应该保留"set"部分,就像在基类中一样.如果尝试实例化B类并为TestString分配一个值,它将使用A类的实现,这就是发生的情况.

Since properties are just pairs of functions (get_PropName(), set_PropName()) overriding only the "get" part should leave the "set" part as it is in the base class. And this is just what happens if you try to instanciate class B and assign a value to TestString, it uses the implementation of class A.

但是,如果我以反射的方式看待B类的实例化对象,将会发生以下情况:

But what happens if I look at the instantiated object of class B in reflection is this:

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

如果我尝试通过以下方式从反射中调用设置器:

And if I try to invoke the setter from reflection with:

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

我什至会收到带有以下消息的ArgumentException:

I'll even get an ArgumentException with the following message:

找不到属性设置方法.

Property set method not found.

这符合预期吗?因为我似乎找不到用于GetProperty()方法的BindingFlags组合,该方法通过反射将返回的属性与有效的get/set对返回给我.

Is this as expected? Because I don't seem to find a combination of BindingFlags for the GetProperty() method that returns me the property with a working get/set pair from reflection.

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

I would expect that behaviour if I'd use BindingFlags.DeclaredOnly on GetProperties() but the default (BindingFlags.Default) takes inherited members into account and the setter of TestString clearly is inherited!

推荐答案

有一种解决方法:

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)更加小心.

This approach should be reasonably robust. You will need to be more careful with this (BindingFlags) if you're looking for non-public accessor(s).

请注意,此方法与硬编码" typeof(A).GetProperty("TestString")typeof(B).BaseType.GetProperty("TestString")不同,因为它可以找到声明所涉及属性的实际原始类型.由于派生类型不可能(至少在C#中不是)将新的访问器 add 添加到重写的属性,因此对此原始"类型的属性声明应包含所有相关的访问器.

Note that this approach is different from "hardcoding" typeof(A).GetProperty("TestString") or typeof(B).BaseType.GetProperty("TestString") because it finds the actual, original type that declares the property in question. Since it isn't possible (not in C# at least) for a derived type to add new accessors to an overridden property, the property-declaration on this "original" type should contain all the relevant accessors.

这篇关于具有覆盖属性和反射的奇怪效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆