ClosedXML.ReportでExcelにデータを書き込む

# はじめに
ClosedXMLをつかってExcelを操作するなどの記事はいくつか散見しますが、「ClosedXML.Report」の使い方を解説した記事はなかなか無いので、本記事で少し解説しようと思います。


# ClosedXML.Reportとは
「ClosedXMLとは」の説明と被るので、詳しくは他の記事等を参照してください。
簡単に言うと、ExcelがインストールされていなくてもExcelファイルを操作できるライブラリです。
通常は、COMコンポーネットを参照して使うのですが、それにはExcelがインストールされている必要があります。ClosedXMLではその必要がなくなります。

https://closedxml.github.io/ClosedXML.Report/

# 何が違う？
ClosedXMLとClosedXML.Reportで何が違うのかについてですが、例えばテーブルデータをExcelに書き込む場合、下記にのように、行と列のForループを回して各セルに入力するように実装するかと思いますが、ClosedXML.Reportではその必要がなくなり、より効率的になります。
何より、安易に何重にもループを回したりするのは個人的に「んー...」と思ってしまいます。わかりやすいので悪いことではないですが。

```csharp
// 普通にClosedXMLだけ使う場合
var wkb = new XLWorkbook();
var wsh = wkb.Worksheet("Sheet1");

var data = new[]
{
    Enumerable.Range(1,5).ToArray(),
    Enumerable.Range(2,5).ToArray(),
    Enumerable.Range(3,5).ToArray(),
};

for (int i = 0; i < data.Count(); i++)
{
    for (int j = 0; j < data[i].Count(); j++)
    {
        wsh.Cell(i + 1, j + 1).Value = data[i][j];
    }
}
```


# ClosedXML.Reportを使う
では、本題です。本記事ではExcelがインストールされていないことを前提に、話を進めます。
あってもOKです。

## まずはNuGetがらインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684408/a90ba80d-54bf-360d-5554-e6fe84d3f664.png)

```csharp
using ClosedXML.Excel;
using ClosedXML.Report;
```

## テンプレートとなるExcelファイルを生成する
Excelにデータを流し込むオブジェクトを用意する。オブジェクトは下記の例だと匿名型を使ってはいるが、普通にクラスを用意して、使うこともできる。
次にテンプレートとなるブックを生成する。オブジェクトのValuesプロパティはコレクションなので、セルA1に"{{item}}"と入力しておく（値が一つなら、"{{item.Values}}"でOK）。
さらに、ブックに名前を定義しておく。Dataプロパティの参照範囲とValuesプロパティの参照範囲を定義する。
これで、準備OK。


```csharp
// 匿名クラス（ちゃんとクラスを作ってもよい）
var obj = new
{
    Data = new[]
    {
        new { Values = Enumerable.Range(1,5) },
        new { Values = Enumerable.Range(2,5) },
        new { Values = Enumerable.Range(3,5) }
    }
};

// ブックを生成
using (var wkb = new XLWorkbook())
{
    // シート追加
    var wsh = wkb.Worksheets.Add("Sheet1");
    //セルに入力
    wsh.Cell("A1").Value = "{{item}}";
    // ブックにプロパティの名前を定義する。
    wkb.NamedRanges.Add("Data", wsh.Ranges("A1:B2"));
    wkb.NamedRanges.Add("Values", wsh.Ranges("A1"));
}

```

Excelがあるなら、あらかじめテンプレートファイルを用意しておくのもあり。
（上記ブックをエクセルで開くと以下のようになる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684408/2b20154d-7307-7ecd-9661-6ebbbe4a3db9.png)


## ③テンプレートにデータを流し込む
XLTemplateクラスのコンストラクタに、先ほどのブックのオブジェクト、またはテンプレートのExcelファイルがあるならそのパスを渡します。AddVariableメソッドに流し込むデータオブジェクトを渡し、Generateメソッドでデータがエクセルに生成されます。


```csharp

    // テンプレートを作成
    using (var template = new XLTemplate(wkb))
    {
        // テンプレートにオブジェクトを突っ込む
        template.AddVariable(obj);
        template.Generate();
        // 保存
        template.SaveAs("result.xlsx");

    }
```

実行すると↓↓↓のようなExcelが出来上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684408/2c93e680-485e-9caa-3373-ecc945e38c25.png)

# 別の例
上記では、簡単な例を示しましたが、名前をちゃんと定義すれば下記のようにもできます。

```csharp

var obj = new
{
    ColumnNames = new[] { "名前", "年齢", "性別" },
    Data = new[]
    {
        new { Name = "颯太", Age = 20, Sex = "男性" },
        new { Name = "結衣", Age = 18, Sex = "女性" },
        new { Name = "海斗", Age = 22, Sex = "男性" },
        new { Name = "香織", Age = 21, Sex = "女性" },
    }
};

// ブックを生成
using (var wkb = new XLWorkbook())
{
    var wsh = wkb.Worksheets.Add("Sheet1");

    wsh.Cell("A1").Value = "{{item}}";
    wsh.Cell("A2").Value = "{{item.Name}}";
    wsh.Cell("B2").Value = "{{item.Age}}";
    wsh.Cell("C2").Value = "{{item.Sex}}";

    wkb.NamedRanges.Add("Data", wsh.Ranges("A2:C3"));
    wkb.NamedRanges.Add("ColumnNames", wsh.Ranges("A1"));
}

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684408/1aff73ea-de60-7a62-e37f-72b48d8e14db.png)

# まとめ
ClosedXML.Reportを使うことで、ループを回さなくともExcelにデータを書き込むことができました。
GitHubにサンプルが色々とあるので、参照してみてください。

https://github.com/ClosedXML/ClosedXML.Report