在 C# 中,重写自动属性并仅提供一个访问器通过以下方式进行反射PropertyInfo
“失去”另一个,即使它是在基类中定义的。
乍一看可能很奇怪,但似乎是合理的经过更详细的分析。
然而,改变override
to sealed override
还更改了此行为并允许获取所有访问器:
using System.Reflection;
using NUnit.Framework;
[TestFixture]
public class PropertySealedOverrideReflectionTests
{
public class Base
{
public virtual object Override { get; set; }
public virtual object SealedOverride { get; set; }
}
public class Derived : Base
{
public override object Override { set => base.Override = value; }
public sealed override object SealedOverride { set => base.Override = value; }
}
[Test]
public void Override()
{
PropertyInfo overrideProperty = typeof(Derived).GetProperty(nameof(Derived.Override));
// ---
// getter from base class is "invisible" here
// ---
Assert.False(overrideProperty.CanRead);
Assert.Null(overrideProperty.GetMethod);
}
[Test]
public void SealedOverride()
{
PropertyInfo sealedOverrideProperty = typeof(Derived).GetProperty(nameof(Derived.SealedOverride));
// ---
// after changing to "sealed override" getter is in place
// ---
Assert.True(sealedOverrideProperty.CanRead);
Assert.NotNull(sealedOverrideProperty.GetMethod);
}
}
编译器改变类型是做什么的sealed override
在提供的场景中?这种行为的原因是什么?
在提供的场景中,编译器会改变类型以进行密封覆盖吗?这种行为的原因是什么?
由于“virtual”和“sealed”(或 CLR 术语中的“final”)等属性适用于方法而不是属性,因此编译器密封属性的唯一方法是将其方法标记为密封。但是,如果 setter 和 getter 中的一个丢失怎么办?编译器是否应该将基类型的方法标记为密封的?
不,我想显然不是。 :)
因此,为了让编译器有一种方法可以标记为密封,它必须创建一个方法,即使您没有声明一个方法。
恕我直言,查看反射提供的信息以及代码实际编译的内容很有启发性。这是一个基于您的场景的简单代码示例:
class Base
{
public virtual object P1 { get; set; }
public virtual object P2 { get; set; }
public virtual object P3 { get; set; }
}
class Derived : Base
{
public sealed override object P1 { set => base.P1 = value; }
public override object P2 { set => base.P2 = value; }
}
IE。基类声明了三个虚拟属性,除了名称之外,所有属性都相同。然后,派生类重写其中两个虚拟属性,密封其中之一。
如果您看一下反射返回的描述符对象之间的差异,其中的属性Derived
,你会注意到一些事情:
- 即使我们还没有声明 getter
P1
,反射无论如何都会返回一个,并且DeclaringType
属性返回Derived
type.
- But for
P2
,反射确实not返回一个吸气剂(这与你之前的问题).
- For
P3
,再次返回一个 getter,但是对于这个,DeclaringType
返回Base
type.
- For the
P1
吸气剂,MethodBase.Attributes
包括MethodAttributes.Final
,表明该方法是密封的。这是编译器无法将其放在基类型上的属性(出于明显的原因),因此必须在派生类型中实现该方法,以便该属性有一个生存的地方。
最后,如果我们查看生成的代码,我们会发现,编译器确实不仅为我们创建了这个方法,而且实际上只是直接委托给基类 getter:
.method public hidebysig specialname virtual final
instance object get_P1() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance object TestSO57762322VirtualProperty.Base::get_P1()
IL_0006: ret
} // end of method Derived::get_P1
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)