65.9K
CodeProject 正在变化。 阅读更多。
Home

查看 C# 代码的中间语言

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (53投票s)

2013年6月5日

CPOL

6分钟阅读

viewsIcon

92734

downloadIcon

1976

介绍 'Sil' - 这是一款插件,可让您右键单击代码并快速检查编译器为其生成的通用中间语言。

引言

Sil 是 Visual Studio 的一款插件,可让您快速反编译和检查代码。它是如何工作的?

首先,找到您感兴趣的代码

接下来,右键单击方法名(或属性、类等),然后选择“反汇编

最后,您所选内容的反汇编将在新的文档窗口中显示,并带有一些额外功能,例如显示或隐藏源代码注释的能力

我们为什么要关心反汇编?

1. 解决问题

C# 有很多语法糖——lambda 表达式、linq、using 语句、多播委托等等。有时,如果您正在调查 bug 或问题,查看代码较低层实际发生的情况会有所帮助。

2. 教育

我们学习了许多关于 .NET 和 C# 的知识——这些知识通常是相当高层次的。我们不必关心我们使用的构造会生成什么程序集,这很棒。然而,我们大多数开发人员都是书呆子和修补匠——我们想了解正在发生什么,它是如何工作的,并拓宽我们的知识。我们都知道,即使抛出异常,using 块也会处置其目标 IDisposable 对象——但如何实现?如果我们捕获类型为 System.Exception 的异常并静默消耗它,我们的代码将继续执行——对吗?但如果它是 ThreadAbortException 呢?它会自动重新抛出——如何实现?查看程序集可以教您更多关于 C# 和 .NET Framework 实际工作方式的知识。

在这篇文章中,我将向您展示如何使用 Sil,并描述其工作原理——您可以将代码作为自己 Visual Studio 插件的起点。我还将撰写一系列关于 .NET 开发人员角度的通用中间语言的短篇文章。

让我试试!

如果您已经对通过显微镜疯狂检查每个函数的前景深信不疑,并且想尝试 Sil——只需下载文章顶部的安装程序。Sil 作为 Visual Studio 2010 和 2012 的插件工作,还有一个独立的应用程序,可让您反汇编任何托管程序集。

安装 Sil 后,只需打开任何 C# 代码并右键单击您感兴趣的内容。如果它是方法名,则该方法将被反汇编。这同样适用于属性、字段、事件、委托、枚举和许多其他构造。如果 Sil 无法确定您要反汇编的具体内容,它将为您反汇编整个程序集。

独立应用程序

您可以将 Sil 作为独立应用程序运行。打开它并选择“文件 > 反汇编”,或者直接将程序集拖放到主窗口中。独立应用程序的一个有用功能是,整个程序集内容将作为结构化树显示在主窗口的左侧,这使您可以轻松地在程序集中查找内容。

Sil 的工作原理

Sil 并不是很智能。它分解为几个基本组件。

Sil API

这个类库提供了核心功能,一个用于反汇编程序集的对象(它创建一个 DisassembledAssembly 实例)。除此之外,还定义了一些其他实体,例如 DisassembledClassDisassembledEnumeration

Sil UI

这是一个 WPF 用户控件库,其中包含主要的“SilView”用户控件。此视图用于呈现 DisassembledAssembly。它还提供了一些基本功能(例如打开或关闭注释)。

Sil.SV2010

Visual Studio 2010 插件。它将“反汇编”命令添加到代码编辑器上下文菜单并进行连接。它使用 Sil API 进行反汇编选择的逻辑,并使用 Sil UI 在工具窗口中呈现它。

Sil.SV2012

Visual Studio 2012 插件。它将“反汇编”命令添加到代码编辑器上下文菜单并进行连接。它使用 Sil API 进行反汇编选择的逻辑,并使用 Sil UI 在工具窗口中呈现它。

Sil

独立应用程序。这是一个 WPF 应用程序,它使用 API 反汇编程序集,并通过 Sil UI 呈现它。

Sil 还使用了一些其他外部组件。

ildasm

来自 Microsoft 的 ildasm 工具用于实际反汇编程序集。

AvalonEdit

出色的 AvalonEdit 库用于创建语法高亮显示程序集文本编辑器窗口。

使用 API

您可以使用 Visual Studio 插件或独立应用程序,但如果您愿意,也可以直接使用 API,我将通过几个简单的示例重点介绍该库的使用方式。

示例 1:反汇编程序集

在此示例中,我们使用 SilAPI 中的 Disassembler 对象来创建 DisassembledAssembly。然后我们将原始 IL 写入文件。

//  Disassemble the assembly.
DisassembledAssembly disassembledAssembly = 
        Disassembler.DisassembleAssembly(@"SomeAssembly.dll");
 
//  Write out the assembly to a file.
using(var stream = new FileStream(@"SomeAssembly.il", FileMode.Create, FileAccess.Write))
using (var writer = new StreamWriter(stream))
{
    writer.Write(disassembledAssembly.RawIL);
}

一些要点

  • 如果您使用 Sil,Disassembler 是一个您会经常使用的对象——它是实际执行反汇编操作的类。
  • DisassembledAssembly 不仅包含原始 IL,还包含类、结构、事件等。

示例 2:发现程序集中的类

DisassembledAssembly 对象包含程序集内容的图。这意味着您可以枚举程序集的各种元素。

//  Disassemble the assembly.
DisassembledAssembly disassembledAssembly = 
                     Disassembler.DisassembleAssembly(@"SomeAssembly.dll");
 
//  Go through each class.
foreach (var disassembledClass in disassembledAssembly.Classes)
{
    //  Write out some details on the class.
    Console.WriteLine("Found class: " + disassembledClass.ShortName);
    Console.WriteLine("Fields: " + disassembledClass.Fields.Count());
    Console.WriteLine("Methods: " + disassembledClass.Methods.Count());
}

程序集上的一些有用属性如下

  • Classes:程序集中定义的类
  • AllClasses:程序集中定义的类,包括嵌套类
  • Structures / AllStructures:获取程序集中的结构,可选地包括嵌套结构
  • Interfaces / AllInterfaces:获取接口
  • Delegates / AllDelegates:获取委托
  • Enumerations / AllEnumerations:获取枚举
  • AllFields:获取所有对象中的所有字段
  • AllProperties:获取所有对象中的所有属性
  • AllEvents:获取所有对象中的所有事件
  • AllMethods:获取所有方法

示例 3:在程序集中搜索实体

在像 Visual Studio 插件这样的客户端应用程序中,我们通常知道我们要查找的长名称以及它是什么(例如,当用户右键单击类时,我们知道他们选择的是一个类以及它的完整名称)。API 公开了一个用于搜索程序集的方法。

public static void SearchAssembly()
{
    //  Disassemble the assembly.
    DisassembledAssembly disassembledAssembly = 
                         Disassembler.DisassembleAssembly(@"SomeAssembly.dll");
 
    //  Create a disassembly target that targets the interface named 'ISomeInterface'.
    DisassemblyTarget target = new DisassemblyTarget
              (DisassemblyTargetType.Interface, @"SimeAssembly.ISomeInterface");
 
    //  Search for the interface.
    DisassembledEntity entity = disassembledAssembly.FindDisassembledEntity(target);
 
    //  If we found it, show the IL.
    if(entity != null)
        Console.WriteLine(entity.RawIL);
} 

下一步?

从这里开始,我的计划是撰写一系列关于通用中间语言的短篇文章,作为那些可能想了解更多信息的人的参考。我对 Sil 也有一些计划。目前在路线图上,我正在考虑

  1. 自动“注释”功能——如果您选择一行程序集,屏幕底部会有其含义的易读描述。
  2. 反汇编选定代码的能力,例如,方法中的几行。
  3. 在插件中支持程序集树,而不仅仅是独立应用程序。

如果您对某个功能有特别的需求或想参与其中,请联系我们!您可以在 GitHub 上找到代码:github.com/dwmkerr/sil

已知问题

使用 Sil 时需要注意一些问题。

  1. 不支持 Visual Basic。它可能有效——我没有尝试过。对 VB 的支持不在路线图上,但如果我收到足够多的请求,我一定会添加它。
  2. 我发现反汇编模板类时有一些奇怪之处——有时,找不到正确的类。这将很快解决,您可以在 GitHub 上关注进度。
  3. 您正在处理的项目必须已构建并保持最新,Sil 才能反汇编它。如果您更改了代码,请在运行 Sil 之前构建它。

历史

  • 2013 年 6 月 7 日:初始版本
© . All rights reserved.