为什么 C# 复制中属性的密封重写不会重写基类型的访问器?

2023-11-29

在 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,你会注意到一些事情:

  • 即使我们还没有声明 getterP1,反射无论如何都会返回一个,并且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(使用前将#替换为@)

为什么 C# 复制中属性的密封重写不会重写基类型的访问器? 的相关文章

  • Mono C# 获取应用程序路径

    我正在寻找我的应用程序的目录 它似乎与常规 c 不同 As in Path GetDirectoryName Application ExecutablePath 不管用 一种正确的跨平台解决方案是 Path GetDirectoryNam
  • 如何获取列表框中项目的索引?

    我正在将项目添加到ListBox像这样 myListBox Items addRange myObjectArray 我还想通过以下方式选择我添加的一些项目 foreach MyObject m in otherListOfMyObject
  • 为什么Java不支持C中的clrscr这样的函数?

    我有一个问题 对很多人来说可能听起来很愚蠢 但我不能停下来把它发布在这里 因为在互联网上找不到任何东西 为什么java没有我们在C中使用的clrscr之类的函数 如果我创建了一个基于用户输入反复迭代的 java 控制台应用程序 然后如果我想
  • 如何在 Mac OS X 中获取 aio 信号处理程序的用户数据

    我尝试在 Mac OS X 下使用 aio 函数进行异步文件 IO 但在将某种形式的用户数据输入信号处理程序时遇到问题 这是设置操作的代码 class aio context public aio context int fildes bo
  • 在 C# 中将 Exe 文件作为嵌入式资源运行

    我有一个第 3 方 EXE 我只需要从我的 C 应用程序运行它 我的主要目标是对我的 C 文件中的第 3 方可执行文件进行版权保护 有没有更好的方法来做到这一点 我怎样才能做到这一点 首先将嵌入的可执行文件作为资源文件添加到您现有的资源文件
  • 无法将 User32.dll 导入 Visual Studio

    I tried To add 用户32 dll from 参考管理器 并将其导入自Windows System32 user32 dll I got 错误信息 无法添加对 C Windows System32 user32 dll 的引用
  • 如何将外部文件添加到应用程序文件(clickonce / .NET)

    我在用着 发布 vs2008 中的选项 我很高兴它的工作原理 现在我想添加 2 个外部 exe 文件到已安装的包中我注意到按钮 应用程序文件 在发布选项卡上 但似乎不允许手动添加新文件 我已经玩过这个并找到了存档的方法 1 将EXE文件作为
  • 如何在类中使用常量类变量声明常量数组?

    如何在类中使用常量类变量声明常量数组 是否可以 我不想要动态数组 我的意思是这样的 class test const int size int array size public test size 50 int main test t 5
  • 对于相同的数据库对象,实体框架对象引用是否相同

    如果我从不同位置查询 逻辑上 在数据库中 相同的对象 实体框架是否返回相同的对象引用 例如 我查询了名为 Joe Black 的客户 并假设现在我知道数据库中只有一个 Joe Black Customer c select blabla w
  • 在异步方法中显示错误消息的更好方法

    事实上我们不能使用await关键字在catch块使得在 WinRT 中显示来自异步方法的错误消息变得非常尴尬 因为MessageDialogAPI 是异步的 理想情况下我希望能够这样写 private async Task DoSometh
  • Caliburn.Micro 事件聚合器

    如果这是一个非常愚蠢的问题 请道歉 但我刚刚开始使用 caliburn micro 我正在努力获取 eventAggregator 似乎没有任何内容订阅 我不确定问题是出在视图模型还是引导程序上 这是视图模型 class MainWindo
  • OpenMP while 循环中的手动同步

    我最近开始使用 OpenMP 为大学的一个项目做一些 研究 我有一个矩形且均匀分布的网格 在该网格上我使用迭代方案求解偏微分方程 因此 我基本上有两个 for 循环 网格的 x 方向和 y 方向各一个 并由 while 循环包裹以进行迭代
  • xaml.cs 文件上的 InitializeComponent() 出现错误

    有时我会收到一个红色错误 内容如下 InitializeComponent 在当前上下文中不存在 以及我的其他变量 xaml受约束的x Name The x ClassXaml 文件中的名称空间和类名确实对应于我的xaml cs file
  • Oracle DataAccess 相关:“动态程序集中不支持调用的成员。”

    据我了解 此类错误已在 SO 上讨论过多次 有些人认为这是 DLL 文件中的错误 有些人通过更改 DLL 版本来解决 其他人似乎没有任何线索 无论如何 我只是发帖试试运气 在 C GUI 上的网格中选择一行时 我的应用程序崩溃了 stack
  • C++中main函数可以调用自身吗?

    谁能告诉我下面的代码有什么问题吗 int main return main 我测试了一下 编译正确 它永远运行 幕后还有什么阴谋吗 TLDR 呼叫main导致未定义的行为 标准中使用的术语以及对程序员和编译器的影响似乎存在混淆 首先 单独的
  • 创建 MSI 的最佳工具[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我是设置项目创建的新手 现在我正在使用 Visual Studio 2008 为我的项目创建安装文件 msi 我对在安装向导中创建自己的自
  • C#无循环方式将字符串拆分为多维数组或锯齿状数组

    如何在不循环的情况下将字符串拆分为多维数组或锯齿状数组 我看到一个代码片段 其中有人使用文件流执行此操作 但我不知道如何使其适用于我的字符串 我的字符串类似于1 2 3 1 4 1并可以分为ID Qty 这是我看到的代码 string li
  • 在 '*' 标记之前编译“错误:预期 ')' 时出现多个相同错误

    我正在尝试用 C 语言编程 当我使用以下参数进行编译时 gcc D BSD SOURCE Wall ansi pedantic g tokenizer c FileOccur c WordList c wordstat c indexer
  • 如何检查应用程序的 .NET 版本?

    除了在仅具有 NET Framework 版本 3 5 的计算机上运行之外 如何检查 NET 应用程序的版本 NET 框架版本控制在 NET 2 0 之后变为 foobar 一个应用程序的目标是CLR版本 它使用 EXE 的程序集元数据来实
  • 用 C# 解析和查询 SOAP

    我正在尝试解析一个大量命名空间的 SOAP 消息 源也可以在here http tinyurl com n3av6k

随机推荐