c# - 为什么向 void 返回方法添加返回类型会导致 MissingMethodException

标签 c# .net clr

我有一个 .NET 应用程序,它使用一个定义某些方法的程序集 (.dll):

    public void DoSomething()
    {
        // Do work
    }

假设此方法签名更改为包含一个字符串 返回类型:

    public string DoSomething()
    {
        // Do work
        return "something";
    }

为什么使用此方法的代码会因 System.MissingMethodException 而失败?

在我看来,在这个方法的所有调用点,都没有使用返回值(因为它之前不存在)。

为什么这个更改会破坏代码?

最佳答案

声明您已更改方法签名并因此必须重新编译调用者的其他答案是正确的。我想我可能会添加一些关于你这个问题的额外信息:

It seems to me, that at all call sites to this method, no use was made of the return value (since it did not exist before).

完全正确。现在,考虑这个问题:如何编写不使用数据的代码?您似乎在完全错误的假设下工作,即不使用值 不需要代码,但不使用值肯定需要代码!

假设你有方法:

static int M1(int y) { return y + 1; }
static void M2(int z) { ... }

你有一个电话

int x;
x = M1(123);

在 IL 级别发生了什么?以下内容:

  • 在临时池上为 x 分配空间。
  • 将 123 压入堆栈
  • 调用 M1。
  • 将 1 压入堆栈。堆栈现在是 1, 123
  • 添加栈顶的两个东西。这会同时弹出并推送结果。堆栈现在是 124。
  • 返回调用者
  • 堆栈仍然是 124。
  • 将堆栈上的值存储到 x 的临时存储器中。这会弹出堆栈,因此堆栈现在为空。

假设你现在做:

M1(345);

会发生什么? 同样的事情:

  • 将 345 压入堆栈
  • 调用 M1。
  • 将 1 压入堆栈。堆栈现在是 1, 345
  • 添加栈顶的两个东西。这会同时弹出并推送结果。堆栈现在是 346。
  • 返回调用者
  • 栈还是346。

但是没有任何指令将值存储在堆栈中的任何地方,所以我们必须发出一条弹出指令:

  • 将未使用的值从堆栈中弹出。

现在假设你调用

M2(456);

会发生什么?

  • 将 456 压入堆栈
  • 调用 M2。
  • M2 发挥作用。当它返回给调用者时,堆栈是空的,因为它是 void 返回。
  • 堆栈现在是空的,所以不要弹出任何东西。

现在您明白为什么将方法从 void 返回更改为 value 返回是一个破坏性更改了吗? 现在每个调用者都必须将未使用的值从堆栈中弹出。对数据什么都不做仍然需要将其从堆栈中清除。如果你不弹出那个值,你就是在错位堆栈; CLR 要求堆栈在每条语句的开头为,以确保不会发生这种错位。

关于c# - 为什么向 void 返回方法添加返回类型会导致 MissingMethodException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9178533/

相关文章:

c# - 依赖注入(inject)和项目引用

.net - 什么是 webclient 以及 webclient 在 .net 中的用途

c# - 如何将office文件转换成图片

c# - IE8 不会在启用 UAC 的情况下下载具有自定义 MIME/类型的文件

c# - HostingEnvironment.QueueBackgroundWorkItem - 澄清?

c# - 保护区与在基类中使用私有(private)区域

.net - 捕获 Windows 服务 C# 中的所有异常

c# - 是否可以将标有 MethodImplOptions.InternalCall 的方法链接到它的实现?

c# - 多线程 - 等待所有线程收到信号

c# - 弄清楚如何摆脱 UITableView 单元格中单元格周围的边框