为什么 C# 接口方法不声明为抽象或虚拟?

2023-11-24

接口中的 C# 方法的声明不使用virtual关键字,并在派生类中重写而不使用override关键词。

是否有一个原因?我认为这只是一种语言便利,显然 CLR 知道如何在幕后处理这个问题(默认情况下方法不是虚拟的),但是还有其他技术原因吗?

下面是派生类生成的 IL:

class Example : IDisposable {
    public void Dispose() { }
}

.method public hidebysig newslot virtual final 
        instance void  Dispose() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Example::Dispose

请注意该方法已声明virtual final在伊利诺伊州。


对于接口,添加abstract,甚至是public关键字是多余的,因此您可以省略它们:

interface MyInterface {
  void Method();
}

在CIL中,该方法被标记为virtual and abstract.

(注意Java允许声明接口成员public abstract).

对于实现类,有一些选项:

不可重写:在 C# 中,类没有将方法声明为virtual。这意味着它不能在派生类中被重写(只能隐藏)。在 CIL 中,该方法仍然是虚拟的(但密封的),因为它必须支持有关接口类型的多态性。

class MyClass : MyInterface {
  public void Method() {}
}

可重写:在 C# 和 CIL 中,该方法都是virtual。它参与多态调度并且可以被覆盖。

class MyClass : MyInterface {
  public virtual void Method() {}
}

Explicit:这是类实现接口但不在类本身的公共接口中提供接口方法的一种方式。在 CIL 中,该方法将是private(!) 但仍然可以从类外部通过对相应接口类型的引用来调用它。显式实现也是不可重写的。这是可能的,因为有一个 CIL 指令(.override),它将把私有方法链接到它正在实现的相应接口方法。

[C#]

class MyClass : MyInterface {
  void MyInterface.Method() {}
}

[CIL]

.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
  .override MyInterface::Method
}

在 VB.NET 中,您甚至可以在实现类中为接口方法名称添加别名。

[VB.NET]

Public Class MyClass
  Implements MyInterface
  Public Sub AliasedMethod() Implements MyInterface.Method
  End Sub
End Class

[CIL]

.method public newslot virtual final instance void AliasedMethod() cil managed
{
  .override MyInterface::Method
}

现在,考虑这个奇怪的情况:

interface MyInterface {
  void Method();
}
class Base {
  public void Method();
}
class Derived : Base, MyInterface { }

If Base and Derived在同一个程序集中声明,编译器将使Base::Method虚拟和密封(在 CIL 中),即使Base不实现该接口。

If Base and Derived编译时位于不同的程序集中Derived程序集,编译器不会更改其他程序集,因此它将引入一个成员Derived这将是一个明确的实现MyInterface::Method这只会将调用委托给Base::Method.

所以你看,every接口方法实现必须支持多态行为,因此必须在 CIL 上标记为 virtual,即使编译器必须经过一系列的操作才能做到这一点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 C# 接口方法不声明为抽象或虚拟? 的相关文章

  • 将复选框添加到 UniformGrid

    我正在尝试将复选框动态添加到 wpf 中的统一网格中 但看起来网格没有为它们分配足够的空间 所以它们都有点互相重叠 这就是我将它们添加到后面的代码中的方法 foreach string folder in subfolders PathCh
  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • Qt-Qlist 检查包含自定义类

    有没有办法覆盖加载自定义类的 Qt QList 的比较机制 即在 java 中你只需要重写一个比较方法 我有一个带有我的自定义类模型的 QList QList
  • 如何避免情绪低落?

    我有一个实现状态模式每个状态处理从事件队列获取的事件 根据State因此类有一个纯虚方法void handleEvent const Event 事件继承基础Event类 但每个事件都包含其可以是不同类型的数据 例如 int string
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • 如何使用 std::string 将所有出现的一个字符替换为两个字符?

    有没有一种简单的方法来替换所有出现的 in a std string with 转义 a 中的所有斜杠std string 完成此操作的最简单方法可能是boost字符串算法库 http www boost org doc libs 1 46
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif

随机推荐

  • 在 Java 中以 1000 个线程递增 AtomicInteger 不会生成值 1000 [重复]

    这个问题在这里已经有答案了 我正在执行一个java代码 其中我有一个AtomicInteger其中 1000 个线程正在尝试执行incrementAndGet 我预计最终值为 1000 但每次运行都会生成各种不同的值 代码如下 class
  • 如何在 JGit 中“git log --follow ”? (检索完整历史记录,包括重命名)

    我必须如何扩展以下 logCommand 才能获得 follow的选项git log命令工作 Git git new Git myRepository Iterable
  • 有关 asp.net mvc 上的 C# 和 bool 的帮助

    根据值打印 是 或 否 的最佳方法是什么 在我看来我想打印出来 模型 isStudent 我不想要 True 或 False 我想要 Yes 或 No 我必须写 if else 语句吗 编写一个辅助方法 public static clas
  • 更改嵌套记录中的属性值

    是否可以使用with关键字创建嵌套记录的新实例 其嵌套属性具有不同的值 两种情况 简单属性和集合 让我们看一个例子 class Program static void Main string args var company new Com
  • d3.js - 堆积条形图中的第 2 组数据值

    我有以下 csv 数据 date scanned unscanned compid sbu 01 2014 10 90 101 f r 02 2014 55 40 101 f r 03 2014 45 23 101 f r 04 2014
  • 太阳路径的计算

    我正在编写几种计算太阳穿过特定点的路径所需的方法 我使用两个不同的源编写代码进行计算 但都没有产生所需的结果 来源是 http www pveducation org pvcdrom properties of sunlight suns
  • Thymeleaf 使用 th:each 动态创建表单

    我想知道如何创建使用的表单th object对于循环中的每个对象th each 例如 我有以下代码 HTML
  • 异步回发不会导致 document.ready 被执行

    我必须对几个页面中使用的用户控件进行一些更改 用户控件包含一些 JQuery 来处理分页任务 显示 3 个月的数据并一次隐藏 9 个月 当控件加载时 它会自动显示当前季度并执行 document ready 中的这段代码 我遇到的问题是 在
  • 使用 OpenCV 进行模式识别

    我正在尝试检测绿色田野上的物体上的图案 该图案由三种颜色组成 两侧有两个粉色标记 中间有一个蓝色标记 排列得像交通灯一样 起初 我尝试将网络摄像头的图像转换为 HSV 色彩空间 并使用 cvInRangeS 隔离颜色 但随着白天房间内光线的
  • 如何选择活动模型序列化器关系所需的属性

    我正在使用JSONAPI格式随着主动模型序列化器创建一个 apiRails API 我有一个序列化器 它显示特定的post那有很多topics目前 在关系下列出了这些主题 目前它只列出了 id 和类型 我也想显示主题的标题 有人会说用inc
  • Android 应用程序发布后,如何向 SQLite 数据库添加新列?

    我想向 SQLite 数据库添加新列 但我已经在 Play 商店上发布了我的应用程序 因此 如果我编辑它 用户需要卸载并重新安装该应用程序 但我不想要那样 请帮忙 我是 Android 新手 1 增加 或简单地更改 您的数据库版本 2 这会
  • 会话验证过滤器,当会话过期时注销用户

    我有一个会话验证过滤器 可以在会话过期时注销用户 这是一段代码 但这不起作用 不起作用意味着即使会话过期也不会重定向到登录页面 请帮我解决这个问题 public void doFilter ServletRequest request Se
  • 移位 Swift 数组

    颜色阵列 let colorArray UIColor redColor UIColor orangeColor UIColor yellowColor UIColor greenColor UIColor blueColor 目标是shi
  • 如何将 JQuery-UI 与 Aurelia 结合使用

    我使用 Aurelia CLI 启动了一个新的 Aurelia 应用程序 我按照 Aurelia 文档中的说明安装了 JQuery 并配置了 aurelia json http aurelia io hub html doc article
  • Paypal 自适应付款返回网址调用两次

    我已经实现了贝宝自适应支付方法并使用网络流程 付款后 当我明确单击返回按钮时 返回网址会调用两次 但如果我等待自动重定向 则它只会调用一次 我无法理解为什么 return url 调用了两次 请指教 我正在使用下面的代码 public st
  • 如何将 atan2() 映射到 0-360 度

    atan2 y x 在 180 处有不连续性 顺时针方向切换到 180 0 如何将值范围映射到 0 360 这是我的代码 CGSize deltaPoint CGSizeMake endPoint x startPoint x endPoi
  • 使用较新的 RichEdit 版本?

    我尝试过在 C 上使用 RichTextBox 发现处理数千行长文本时速度太慢 经过一番谷歌搜索 我发现这是因为 net默认使用RichEdit 2 0 解决方案是使用RichEdit 5 0 C RichEditBox 性能极慢 加载 4
  • 颤振主通道问题

    在调试模式下在 IA 模拟器上的 AOSP 上启动 lib main dart 运行 Gradle 任务 assembleDebug 警告 插件 path provider android 需要 Android SDK 版本 31 警告 插
  • 对一个衬垫进行外壳处理以添加到文件中

    这大概是一个复杂的解决方案 我正在寻找一个简单的运算符 例如 gt gt 但用于前置 恐怕它不存在 我必须做类似的事情 mv myfile tmp cat myheader tmp gt myfile 有更聪明的吗 这仍然使用临时文件 但至
  • 为什么 C# 接口方法不声明为抽象或虚拟?

    接口中的 C 方法的声明不使用virtual关键字 并在派生类中重写而不使用override关键词 是否有一个原因 我认为这只是一种语言便利 显然 CLR 知道如何在幕后处理这个问题 默认情况下方法不是虚拟的 但是还有其他技术原因吗 下面是