如何编写更高效的代码?或者,为什么反编译器生成的代码看起来效率不如我编写的代码? [已关闭]

问题描述 投票:0回答:2

在编写我的库时,我使用了一系列三元表达式:

public INumber Level1()
{
  INumber number = Level2();
  Next();
  return
    txt == "-" ?
    new Subtraction(number, Level1()) :
    txt == "+" ?
    new Addition(number, Level1()) :
    txt == "/" ?
    new Division(number, Level1()) :
    txt == "*" ?
    new Multiplication(number, Level1()) :
    number;
}

但是,当我反编译代码时,我发现它变成了一个糟糕的实现(在我看来):

public INumber Level1()
{
  INumber number = Level2();
  Next();
  if (!(txt == "-"))
  {
    if (!(txt == "+"))
    {
      if (!(txt == "/"))
      {
        if (!(txt == "*"))
        {
          return number;
        }
        else
        {
          INumber number2 = new Multiplication(number, Level1());
          result = number2;
        }
      }
      else
      {
        INumber number2 = new Division(number, Level1());
        result = number2;
      }
    }
    else
    {
      INumber number2 = new Addition(number, Level1());
      result = number2;
    }
  }
  else
  {
    INumber number2 = new Subtraction(number, Level1());
    result = number2;
  }
  return result;
}

当我测试我的代码时,测试通过了。

我不明白为什么反编译器产生的输出与我最初编写的不同,而且,我不确定我是否理解如何编写高效的代码。

为什么反编译器生成的 C# 与我编写的不同,我应该做些什么来改变它?

c# conditional-operator cil decompiler
2个回答
1
投票

我不明白为什么会这样

编译器会将你的代码翻译成IL(中间语言),据我所知,这是反编译器的一个怪癖。例如以下内容:

public class C {
    public int M(string txt) => txt == "1"
        ? 1
        : txt == "2"
            ? 2
            : 3;
}

翻译为:

IL_0000: ldarg.1
IL_0001: ldstr "1"
IL_0006: call bool [System.Runtime]System.String::op_Equality(string, string)
IL_000b: brtrue.s IL_001e

IL_000d: ldarg.1
IL_000e: ldstr "2"
IL_0013: call bool [System.Runtime]System.String::op_Equality(string, string)
IL_0018: brtrue.s IL_001c

IL_001a: ldc.i4.3
IL_001b: ret

IL_001c: ldc.i4.2
IL_001d: ret

IL_001e: ldc.i4.1
IL_001f: ret

基于

brtrue.s
代码不会逆转条件。但是多种语言结构可能会导致相同的 IL,因此反编译器需要做一些猜测工作,从而得到您看到的结果。

现在我不明白如何正确编写代码 是否有可能修复它

写得正确,不需要“修复”。至少在某种程度上。

但我没有对布尔值进行反转。

你不应该打扰,编译器应该生成正确的代码(至少通常是这样)。如果您愿意 - 编写一个单元测试来验证行为。

最后但并非最不重要的一点。在这种特殊情况下,

switch
语句表达式)似乎是更合适的结构。例如通过
switch
表达式:

return txt switch 
{
   "-" => Substruction(...),
   "+" => Addition(...),
   // ...
   _ => number
}

0
投票

想必您正在查看反编译器的输出。

反编译器根据程序集的 CIL/MSIL(也称为字节码)生成代码。这与 C# 等高级语言没有 1:1 的关系。

ECMA-335 第三部分包含 CIL 的定义。

研究CIL你会发现没有“三元运算符”指令这样的东西。因此,反编译器会生成看起来像简单比较的代码(

if
语句)。

从根本上来说,一系列

if
语句和三元表达式在运行时是相同的,这两者在中间语言和机器语言中没有区别。

一些反编译器可能会使用 PDB/Debug 信息来帮助生成原始代码,这可能允许反编译器生成三元表达式作为输出,但这本质上是“作弊”,因为无法知道程序员是否使用了三元表达式仅基于 IL 的表达。

您可以使用ildasm等工具来检查代码的IL。

参考文献

© www.soinside.com 2019 - 2024. All rights reserved.