.NET反编译器区分"使用"和"尝试......最后"

Lau*_*ant 13 .net c# cil decompiler

给出以下C#代码,其中以两种不同的方式调用Dispose方法:

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

class Program
{
    static void Main(string[] args)
    {
        using (var disposable1 = new Disposable())
        {
            Console.WriteLine("using");
        }

        var disposable2 = new Disposable();
        try
        {
            Console.WriteLine("try");
        }
        finally
        {
            if (disposable2 != null)
                ((IDisposable)disposable2).Dispose();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一旦使用发布配置编译然后用ildasm反汇编,MSIL看起来像这样:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       57 (0x39)
  .maxstack  1
  .locals init ([0] class ConsoleApplication9.Disposable disposable2,
           [1] class ConsoleApplication9.Disposable disposable1)
  IL_0000:  newobj     instance void ConsoleApplication9.Disposable::.ctor()
  IL_0005:  stloc.1
  .try
  {
    IL_0006:  ldstr      "using"
    IL_000b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0010:  leave.s    IL_001c
  }  // end .try
  finally
  {
    IL_0012:  ldloc.1
    IL_0013:  brfalse.s  IL_001b
    IL_0015:  ldloc.1
    IL_0016:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_001b:  endfinally
  }  // end handler
  IL_001c:  newobj     instance void ConsoleApplication9.Disposable::.ctor()
  IL_0021:  stloc.0
  .try
  {
    IL_0022:  ldstr      "try"
    IL_0027:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_002c:  leave.s    IL_0038
  }  // end .try
  finally
  {
    IL_002e:  ldloc.0
    IL_002f:  brfalse.s  IL_0037
    IL_0031:  ldloc.0
    IL_0032:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0037:  endfinally
  }  // end handler
  IL_0038:  ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)

DotPeekJustDecompile这样的.NET反编译器如何区分使用尝试...最终

Evk*_*Evk 8

它实际上没有什么区别.正如Mark在评论中所说 - 如果你编写的代码与编译器生成的相同using- 反编译器将无法发挥作用.

但是,许多反编译器,包括DotPeek,实际上可以使用调试符号(.pdb)文件来定位实际的源代码,然后使用实际的源代码,这样就不会发生任何反编译.此外,在调试模式下进行编译也可能会影响模式(即 - 您尝试模仿using语句可能在调试与发布编译中产生不同的结果IL).

要防止DotPeek使用您的真实源代码文件,请转到"工具">"选项">"反编译器",然后取消选中"使用符号文件中的源"(如果可用).然后在Release中编译你的代码并观察DotPeek将两个语句反编译为using.