为什么C#copy中属性的密封重写没有从基类型重写访问器?

为什么C#copy中属性的密封重写没有从基类型重写访问器?,c#,.net,reflection,system.reflection,C#,.net,Reflection,System.reflection,在C#中,重写auto属性并仅提供一个访问器会通过PropertyInfo“丢失”另一个,即使它是在基类中定义的 乍一看,它可能看起来很奇怪,但似乎是在经过更详细的分析之后 但是,将覆盖更改为密封覆盖也会更改此行为,并允许获取所有访问者: 使用系统反射; 使用NUnit.Framework; [测试夹具] 公共类PropertySealedOverrideReflectionTests { 公共阶级基础 { 公共虚拟对象重写{get;set;} 公共虚拟对象密封覆盖{get;set;} } 派生

在C#中,重写auto属性并仅提供一个访问器会通过
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;}
}
也就是说,基类声明了三个虚拟属性,除了名称之外,其他都是相同的。然后派生类重写其中两个虚拟属性,并密封其中一个

如果查看由反射返回的描述符对象与
派生的
中的属性之间的差异,您会注意到一些事情:

  • 即使我们没有为
    P1
    声明getter,反射仍然返回一个getter,而
    DeclaringType
    属性返回
    派生的类型
  • 但对于
    P2
    ,反射不会返回getter(这与)
  • 对于
    P3
    ,再次返回一个getter,但是对于这个getter,
    DeclaringType
    返回
    Base
    类型
  • 对于
    P1
    getter,
    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

当名称相同时,您是否看到相同的行为?在基类中表示
覆盖
,在子类中表示
密封覆盖
?在这个例子中,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