为什么C#copy中属性的密封重写没有从基类型重写访问器?
在C#中,重写auto属性并仅提供一个访问器会通过为什么C#copy中属性的密封重写没有从基类型重写访问器?,c#,.net,reflection,system.reflection,C#,.net,Reflection,System.reflection,在C#中,重写auto属性并仅提供一个访问器会通过PropertyInfo“丢失”另一个,即使它是在基类中定义的 乍一看,它可能看起来很奇怪,但似乎是在经过更详细的分析之后 但是,将覆盖更改为密封覆盖也会更改此行为,并允许获取所有访问者: 使用系统反射; 使用NUnit.Framework; [测试夹具] 公共类PropertySealedOverrideReflectionTests { 公共阶级基础 { 公共虚拟对象重写{get;set;} 公共虚拟对象密封覆盖{get;set;} } 派生
PropertyInfo
“丢失”另一个,即使它是在基类中定义的
乍一看,它可能看起来很奇怪,但似乎是在经过更详细的分析之后
但是,将覆盖
更改为密封覆盖
也会更改此行为,并允许获取所有访问者:
使用系统反射;
使用NUnit.Framework;
[测试夹具]
公共类PropertySealedOverrideReflectionTests
{
公共阶级基础
{
公共虚拟对象重写{get;set;}
公共虚拟对象密封覆盖{get;set;}
}
派生的公共类:基
{
公共覆盖对象覆盖{set=>base.override=value;}
公共密封覆盖对象密封覆盖{set=>base.override=value;}
}
[测试]
公共无效覆盖()
{
PropertyInfo overrideProperty=typeof(派生).GetProperty(nameof(派生.Override));
// ---
//基类的getter在这里是“不可见的”
// ---
Assert.False(overrideProperty.CanRead);
Assert.Null(overrideProperty.GetMethod);
}
[测试]
公共空间密封覆盖()
{
PropertyInfo sealedOverrideProperty=typeof(派生).GetProperty(nameof(派生.SealedOverride));
// ---
//更改为“密封覆盖”后,getter已就位
// ---
True(sealedOverrideProperty.CanRead);
Assert.NotNull(sealedOverrideProperty.GetMethod);
}
}
在所提供的场景中,编译器在类型上的更改是如何执行密封覆盖
?这种行为的原因是什么
在提供的场景中,编译器在类型上做了哪些更改以进行密封重写?这种行为的原因是什么
由于诸如“virtual”和“sealed”(或CLR术语中的“final”)等属性适用于方法而不是属性,因此编译器密封属性的唯一方法是将其方法标记为sealed。但是,如果二传手和接球手中的一个或另一个不见了呢?编译器应该将基类型的方法标记为sealed吗
不,我想显然不是
因此,为了让编译器有一个方法标记为sealed,它必须创建一个方法,即使您没有声明一个
嗯,看看反射提供给你的信息以及代码实际编译的目的是很有启发性的。下面是一个基于您的场景的简单代码示例:
类基
{
公共虚拟对象P1{get;set;}
公共虚拟对象P2{get;set;}
公共虚拟对象P3{get;set;}
}
派生类:基
{
公共密封重写对象P1{set=>base.P1=value;}
公共重写对象P2{set=>base.P2=value;}
}
也就是说,基类声明了三个虚拟属性,除了名称之外,其他都是相同的。然后派生类重写其中两个虚拟属性,并密封其中一个
如果查看由反射返回的描述符对象与派生的
中的属性之间的差异,您会注意到一些事情:
- 即使我们没有为
声明getter,反射仍然返回一个getter,而P1
属性返回DeclaringType
派生的类型
- 但对于
,反射不会返回getter(这与)P2
- 对于
,再次返回一个getter,但是对于这个getter,P3
返回DeclaringType
类型Base
- 对于
getter,P1
包括MethodBase.Attributes
,表示方法已密封。这是编译器不能放在基类型上的属性(出于明显的原因),因此必须在派生类型中实现该方法,这样该属性就有了生存的空间MethodAttributes.Final
.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
当名称相同时,您是否看到相同的行为?在基类中表示
覆盖
,在子类中表示密封覆盖
?在这个例子中,sealed应该做的就是防止您在另一个子类中重写,就像派生类的子类无法重写sealedOverrides或者我没有理解您的问题一样。我以这种方式命名属性只是为了说明。在这种情况下,C#编译器确保密封整个属性重写的唯一方法是密封get
和set
访问器。然后为了实现这一点,它必须实际重写get
访问器,即使您没有在重写中编写任何getter。当然,C#编译器只会调用它自己“发明”的访问器中的基本实现。有了反射,就会出现get访问器。@侦探谢谢,但从C#语言的角度来看,sealed override
应该做什么,我提到的问题和行为是通过反射从基类访问属性getter,请参阅问题中的单元测试。备注:对于P3
,您可以在属性info
上看到.DeclaringType
是Base
,即与您询问的类型(保存在.ReflectedType
中)不同。如果您不想在您询问的类中更改任何内容,可以要求“仅声明”,将例如BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public
传递给GetProperty
的相关重载。对于P1
,getter和setter a的MethodBase