Rider 2022.3とReSharper 2022.3のIL Viewerで、ILをC#にデコンパイルできるようになった


# はじめに

Rider 2022.3、そしてReSharper 2022.3からIL Viewerで、ILをデコンパイルしたC#が閲覧できるようになりました。

２形式でデコンパイル可能で、

* high-level（最新の言語機能を使用した記述）
* low-level（シンタックスシュガーな構文を使わない単純な記述）

なC#として閲覧できます。

Webサービス[Sharplab](https://sharplab.io/)で可能だったことが、Rider・ReSharperでもできるようになりましたね。

# 何が嬉しいのか

「C#をコンパイルしたILを読めるのが嬉しいのはわかる。だがそれを再度C#にデコンパイルして何が嬉しいんだ」

と思うかもしれません。

C#はシンタックスシュガー（糖衣構文）が多い言語です。コンパイル結果のILをデコンパイルしたC#を読むことで、シンタックスシュガーを解いた単純なC#を読むことができます。それにより、C#のシンタックスシュガーの内部で、どういうことがおこなわれているか理解できるのが、嬉しいポイントです。

# 機能追加バージョン

機能追加バージョン

* Rider 2022.3から
* ReSharper 2022.3から

# どのようにデコンパイルされるか

この節では、

* C# 11
* .NET 7.0.100
* Mac版のRider 2022.3
 
でのどのようにデコンパイルされたかをスクリーンショットで示します。実際のコードは、本投稿の最後に掲載します。

次のようなレコードがあります。

![スクリーンショット 2022-12-15 21.40.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/15bcaa4f-54de-c2bc-31ef-b83ec2e5cc6f.png)

次のようなメソッドのILを見てみましょう。

![スクリーンショット 2022-12-15 21.23.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/c5d137bc-9c1c-976e-37af-d45e6d5718ef.png)

メニューから、Tools > IL Viewerを選択すると、IL Viewerが開きC#ファイルのILが閲覧できます。先ほどのメソッドのILは次のようになります。雰囲気はわかりますが、難しいですね。私は読めません。

![スクリーンショット 2022-12-15 21.26.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/1ffee572-200e-8833-54f8-76503a9b31f3.png)

IL Viewer Windowの上部のドロップボックスを選択すると

* IL
* Low-Level C#
* High-Level C#

という選択肢が出てきます。

![スクリーンショット 2022-12-15 21.34.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/ed741ef9-ae07-f190-c439-dd9211a438d8.png)

「Low-Level C#」を選ぶと該当メソッドは次のようになります。List型のAddメソッドを呼び出していることに注目してください。「Low-Level C#」のコードを読むことで、「コレクション初期化子が内部でAddメソッドを読み出すこと」をコードを見ながら理解することができます。

![スクリーンショット 2022-12-15 21.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/45c932df-528d-779e-e4f3-e9b291f749c1.png)

「High-Level C#」を選ぶと次のようにな理ます。デコンパイルした結果では実際のコードと異なり、式形式のメソッドが使われていることに注目してください。

![スクリーンショット 2022-12-15 21.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/bc72562a-0674-dcd8-4799-a25d6f44d101.png)

---

次の例は、補完文字列とrecordの分解がどのようにILになり、デコンパイルされるかをみてみましょう。C#のオリジナルコードはこちらです。

![スクリーンショット 2022-12-15 21.47.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/f79cf0aa-4d79-cad8-2094-e1c1c30fb5af.png)

IL（の途中まで）はこちら。長いのでメソッド全ては掲載していません。

![スクリーンショット 2022-12-15 21.47.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/9222e49f-2cab-feaf-a476-9fbfb7b715a5.png)

Low-Level C#（の途中まで）はこちら。分解ではDeconstructメソッドを呼び出していたり、補完文字列にDefaultInterpolatedStringHandlerが使われていることがわかりますね。

![スクリーンショット 2022-12-15 21.48.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/e7ecadca-172a-0980-8211-3c112eddad5b.png)

High-Level C#はこちら。補完文字列がDefaultInterpolatedStringHandlerのままになっています。（雑な予想ですが、デコンパイルが難しいのかもしれません。）

![スクリーンショット 2022-12-15 21.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/d9e0ae80-4721-42ec-2ab8-83ec695eac21.png)


---

最後にrecordが内部でどのようなメソッド・コンストラクター・バッキングフィールド・プロパティーが生成されているのか確認してみましょう。
C#のオリジナルコードはこちら。

![スクリーンショット 2022-12-15 21.40.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/15bcaa4f-54de-c2bc-31ef-b83ec2e5cc6f.png)

IL（の途中まで）はこちら。長いのでメンバ全ては掲載していません。

![スクリーンショット 2022-12-15 21.41.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/577e659d-82f9-0f1b-e452-a53122d18c50.png)

Low-Level C#（の途中まで）はこちら。長いのでメンバ全ては掲載していません。デコンパイルされたC#を見ると、多くのメンバが生成されていることがわかります。

![スクリーンショット 2022-12-15 22.11.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/70b18d5a-f019-a600-3103-9acd646a9bd1.png)


High-Level C#はこちら。

![スクリーンショット 2022-12-15 21.40.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4125/085710df-7cda-dd77-3e62-7c5378e29c55.png)



# まとめ

C#はシンタックスシュガー（糖衣構文）が多い言語です。Rider・ReShaperのIL Viewerの「ILをC#にデコンパイルする」新機能を使い、C#のシンタックスシュガーの内部でどういうことがおこなわれているか理解することができます。

「シンタックスシュガーの内部など、そんなことは知っている」という熟練のC#erも、チームメンバーの教育に役立てることができるかと思います。

Riderはいいぞ！ReSharperもいいぞ！！！

# 公式リンク

* [Rider 2022.3 の新機能](https://www.jetbrains.com/ja-jp/rider/whatsnew/2022-3/)
* [ReSharper 2022.3 の新機能](https://www.jetbrains.com/ja-jp/resharper/whatsnew/2022-3/)


# 今回使ったデコンパイルを試したコード

```csharp
using System;
using System.Collections.Generic;

record Person(
    String Name,
    long Id
);

class Program
{
    static void Main(string[] args)
    {
        var list = new List<Person>
        {
            new("taro", 1L),
            new("jiro", 2L),
            new("saburo", 3L),
        };

        foreach (var person in list)
        {
            ShowPerson(person);
        }
    }

    static void ListSample()
    {
        var list = new List<Person>
        {
            new("taro", 1L),
            new("jiro", 2L),
            new("saburo", 3L),
        };

        Console.WriteLine(list.Count);
    }

    static void ShowPerson(Person person)
    {
        var (name, id) = person;
        var message = $"id: {id} {name}";
        Console.WriteLine(message);
    }
}
```