7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

拡張メソッドを使って自力で、Map を実装する

Posted at

実は次のポストのコンセプトを理解するための、ヤクの毛刈りなのですが、拡張メソッドについて調べてみました。
拡張メソッドは、既存のメソッドや、インターフェイスに対して、後付けでメソッドを生やせる仕組みです。 Ruby とかだと、普通にクラスを書けばそうなりますが、静的言語ではどうなるでしょう?

例えば次のようなクラスがあります。

    public class Employee
    {
        public string Name { get; set; }

        public Employee (string name)
        {
            this.Name = name;
        }
    }

拡張メソッドをつかって、メソッドを追加するように見せる

こいつに対して拡張メソッドを使って、メソッドを追加してみましょう。本体には手を入れずにです。呼び捨ては失礼なので「様」づけするメソッドを追加します。

    static class EmployeeExtensions
    {
        public static string GetNameWithRespect(this Employee self)
        {
            return self.Name + "様";
        }
    }

ここで、のポイントは、static のクラスに、static のメソッドを書いて、(this 型 変数名) の定義をしてあげるだけになります。実際これを呼び出すためのメソッドはこんな感じ

    class Program
    {
        static void Main(string[] args)
        {
            var emp = new Employee("三太夫");
            Console.WriteLine(emp.Name);
            Console.WriteLine(emp.GetNameWithRespect());
            Console.ReadLine();
        }
     }

実行結果は、

三太夫
三太夫様

 完璧!想定通り。しかし、だまされてはいけません、これは、あくまで、static メソッドが、インスタンスメソッドのように見せかけているだけなので、private にはアクセスできませんし、Mock とかするときに、拡張メソッドだったらMockできません。(Mock の回でお話ししました) 
 だから、普通は自分がメンテしているクラスだったら、ちゃんとクラスにインスタンスメソッドを書くべきだと思います。じゃあ、どんな時に良いかというと、インターフェイスに対しても同じようにかけるということらしいです。いつも超絶お世話になっているブログによると、

var input = new[] { 8, 9, 10, 11, 12, 13 };
var output =
    Extensions.Select(
        Extensions.Where(
            input,
            x => x > 10),
        x => x * x);

と、普通に呼び出したら、こうなるところを、こう書けるのがメリットとあります。

var input = new[] { 8, 9, 10, 11, 12, 13 };

var output = input
    .Where(x => x > 10)
    .Select(x => x * x);

これはカッケー。もしかすると、これ使うと、自分で Map や flatMap 書けるんじゃね?

オレオレ Map を実装する

というわけで、C# にない、Map を実装してみましょう。Ruby で大好きだったやつで、イテレーターに関数適用するメソッドです。ちなみに、C# だと、Linq を使えばできますが、そこはあえて実装してみましょう。

先ほどのメソッドに追加

    static class EmployeeExtensions
    {
        public static string GetNameWithRespect(this Employee self)
        {
            return self.Name + "様";
        }
        public static IEnumerable<X> Map<T, X>(this IEnumerable<T> e, Func<T,X> f)
        {
            List<X> x = new List<X>();
            foreach(var element in e)
            {
                x.Add(f(element));
            }
            return x;
        }

    }

単純に、先ほど学んだ 拡張メソッドに対して、引数に Function を渡すようにしています。もともとの型は、どういう型にかわるかわかりませんので、型を変えています。そして、単純に関数適用して、結果を戻しています。
こんなコードをかいてみました。

            var list = new List<int> { 1, 2, 3, 4 };
            var result = list.Map<int, int>(p => p + 1);
            foreach (var e in result)
            {
                Console.WriteLine(e);
            }
            Console.ReadLine();

で結果は?

2
3
4
5

おお!できてる。わしMap 実装しちゃったよ!俺カッケー度が高いテクニックですね。flatMap も同じように実装できるかも! 拡張メソッド理解できるとカッコいいですね!

7
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?