こんにちは。福岡事務所の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もある程度簡単に理解できるようになります。
皆さんもぜひ参考にしてみてください。