LINQ のメソッド名が SQL っぽいからラップする

## SQL チックなメソッド名
C# の *LINQ to Object*（以下、単に LINQ と記載） はとても便利なんですけど、メソッド名が SQL っぽくて、いまいち直感的ではない上にダサいです。例として、JavaScript と比較してみましょう。
| LINQ でのメソッド名 | JavaScript のメソッド名 |
| -- | -- |
| Select | map |
| Where | filter |
| OrderBy | sort |

以下は、実際に利用する例です。
JavaScript ではこう。
```javascript
const hoge = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
const fuga = hoge.filter(x => x % 2 === 0).map(x => x * 2).sort();
```
C# ではこう。
```csharp
var hoge = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
var fuga = hoge.Where(x => x % 2 == 0).Select(x => x * 2).OrderBy(x => x).ToArray();
```
もちろん慣れてくれば `Select` だろうが `Where` だろうがスラスラ読めるのですが、慣れていなければ引っかかるかもしれません。一方、`map`, `filter`, `sort` というのは直感的で意味がわかりやすいです。

## ラップする
ということで、ラッパーメソッドで名前を変えます。
### `Select` => `Map`
```csharp
public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
    => source.Select(x => func(x));

public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> func)
    => source.Select((x, index) => func(x, index));
```
### `Where` => `Filter`
```csharp
public static IEnumerable<T> Filter<T>(this IEnumerable<T> source, Func<bool> func)
    => source.Where(x => func());

public static IEnumerable<T> Filter<T>(this IEnumerable<T> source, Func<T, bool> func)
    => source.Where(x => func(x));

public static IEnumerable<T> Filter<T>(this IEnumerable<T> source, bool func)
    => source.Where(x => func);
```
### `OrderBy` => `Sort`
```csharp
public static IOrderedEnumerable<TSource> Sort<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
    => sources.OrderBy(keySelector, comparer);

public static IOrderedEnumerable<TSource> Sort<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector)
    => sources.OrderBy(keySelector);

public static IOrderedEnumerable<TSource> SortByDesc<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
    => sources.OrderByDescending(keySelector, comparer);

public static IOrderedEnumerable<TSource> SortByDesc<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector)
    => sources.OrderByDescending(keySelector);
```
ソートに関しては、元の `OrderBy` が、昇順か降順かでメソッドが別れています。昇順のソートが `OrderBy`、降順のソートが `OrderByDescending` なので、それぞれ `Sort`、 `SortByDesc` というメソッド名でラップしましたが、ここは昇順か降順かをオプション引数で切り替える `Sort` という名前のメソッドにしても良いでしょう。

「昇順か降順かをメソッド名だけで判断できる」という利点はありますが、同じようなことが別の名前のメソッドで定義されているのも、個人的には気持ち悪いと感じます。

同様に、`ThenBy` と `ThenByDescending` も `Then` というメソッドでラップしてみます。
```csharp
public static IOrderedEnumerable<TSource> Sort<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool byDesc)
    => byDesc ? sources.OrderByDescending(keySelector, comparer) 
              : sources.OrderBy(keySelector, comparer);

public static IOrderedEnumerable<TSource> Sort<TSource, TKey>(this IEnumerable<TSource> sources, Func<TSource, TKey> keySelector, bool byDesc)
    => byDesc ? sources.OrderByDescending(keySelector)
              : sources.OrderBy(keySelector);

public static IOrderedEnumerable<TSource> Then<TSource, TKey>(this IOrderedEnumerable<TSource> sources, Func<TSource, TKey> keySelector, IComparer<TKey> comparer, bool byDesc)
    => byDesc ? sources.ThenByDescending(keySelector, comparer)
              : sources.ThenBy(keySelector, comparer);

public static IOrderedEnumerable<TSource> Then<TSource, TKey>(this IOrderedEnumerable<TSource> sources, Func<TSource, TKey> keySelector, bool byDesc)
    => byDesc ? sources.ThenByDescending(keySelector)
              : sources.ThenBy(keySelector);
```
オプション引数 `byDesc` を設定しました。これにより、次のようにコードを書けます。
```csharp
// ラップ前
var hoge = GetEmployee.OrderBy(s => s.Age).ThenByDesc(x => x.Salary);

// ラップ後
var hoge = GetEmployee.Sort(s => s.Age).Then(s => s.Salary, byDesc: true);
```
もちろん引数名の `byDesc` を省略することもできますが、理由があり記載しています。理由については、以下の記事で解説しているので、よかったらご覧ください。

https://qiita.com/apashoni/items/b8c10e75b8219720efa7

## 比較
メソッド名をラップしてみることで、冒頭のコードは次のように書けるようになりました。
```csharp
// 変更前
var hoge = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
var fuga = hoge.Where(x => x % 2 == 0).Select(x => x * 2).OrderBy(x => x).ToArray();

// 変更後
var hoge = new[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
var fuga = hoge.Filter(x => x % 2 == 0).Map(x => x * 2).Sort(x => x).ToArray();
```
LINQ にあまり慣れていない人でも、よりスッと入ってきやすいコードになったのではないでしょうか。

## その他
ブログとCrieitでも記事を公開しているので、よければご覧ください。

ブログ：BOYISH KINGDOM

https://boyi.sh

Crieit：apashoni

https://crieit.net/users/apashoni