こんにちは。福岡事務所のAです。
今回はソースコードの可読性を高める方法について説明していきたいと思います。

例えばC#で二つのDataTableを比べ、片方のTableにだけ存在するデータを取得したい、
というとき、皆さんはどのようにして処理を書きますか?


TableA TableB
 果物  在庫数  果物  在庫数
リンゴ    100 リンゴ  130
ミカン  120 バナナ  120
バナナ  140 ブドウ  150
ブドウ  150

このTableAとTableBを比べ、TableAにしか存在しない果物(ミカン)のデータのみを取得したい


いくつか方法はありますが、このように考えた方もいるのではないのでしょうか?

・for文やforeach文などを二重にループさせ、
 if文などで果物が両方に存在するかどうかを判定する

しかし、この方法だと以下のようなデメリットがあります。
1. ネスト構造になるため、他の人が見た場合、可読性が低くなる
2. if文が必要になったり、あらかじめTableのレコードの並び順が決まっていないといけないなど、余計なコードが増えたり、前提条件が必要になる

そこで、こういった問題を解決するために最近のC#ではLINQを使用します。
ちなみにLINQとはLanguage INtegrated Query(統合言語クエリ)の略で、
データの集合から特定のデータのみを取得したり、検索や集計などをしてくれる機能です。

ということでさっそくLINQを使用してみましょう。


 var Record = (from rowA in TableA.AsEnumerable()
       where !((from rowB in TableB.AsEnumerable()
              select rowB[“果物”]).Contains(rowA[“果物”]))
       select rowA);

このように記述することで目的が明確になり、
余計なコードやループばかりのコードから処理を推測する必要がなくなります。


目的ごとに分けて説明すると、

 var removal = (from rowB in TableB.AsEnumerable()
              select rowB[“果物”]);

まず、TableBから果物だけのリストを取得します。

 var Record = (from rowA in TableA.AsEnumerable()
       where !(removal.Contains(rowA[“果物”]))
       select rowA);

where にはremoval.Contains(rowA[“果物”])と書くことで、
rowA[“果物”](TableAの果物)がremoval(TableBの果物)のいずれかに
一致するもの(同じ要素)だけを取得します。
しかし、今回はTableAにしか存在しない果物を取得したいので、判定結果に「!」を
付けます。
こうすることでRecordにはミカンの情報のみ格納されます。

selectではTableAのDataRow(果物、在庫数)を取得するように指定しています。


ちなみに判定結果の「!」を消すと、
「TableAとTableB両方に存在する果物のみ取得する」
という処理に変わりますし、TableAとTableBを逆に書くことによって、
「TableBにのみ存在する果物を取得する」という処理に変わったりなど、
少し書き方を変えるだけでいろんな条件でデータを取得することができます。

このようにLINQを使用することでわざわざネストにする必要がなく、
if文などの余計なコードや前提条件も必要なくなるため、可読性が高くなります。

最後に、まとめとしてLINQのメリット、デメリットを挙げておきます。

メリット
・書き方を少し変えるだけで様々な条件でデータを取得することができる
・for文やforeach文と比べて、コードの行数が少なくて済むため、可読性が高くなる

デメリット
・LINQに慣れていない場合、どんなデータを取得しているのか理解するまで時間がかかる

デメリットに関しては、普段からLINQを使っていくうちに自然と慣れてきますし、
人の書いたLINQもある程度簡単に理解できるようになります。

皆さんもぜひ参考にしてみてください。