【C#】拡張メソッドの作り方

# もくじ

https://tera1707.com/entry/2022/02/06/144447

# やりたいこと
仕事で、自作クラスではなく一般的なクラスなのに、msdocsにのっていないクラスメソッドのようなものが出てきて、なんだこれ？となった。何しているのか調べるついでに自分も作れるようになりたい。

# 拡張メソッド
既存の型やクラスに、元の型の変更や継承をすることなく、新たなメソッドを追加できる。

用途としては、たぶん、自分で作ったクラスであれば自分で中にメソッドを追加して機能拡張できるが、そうそういじることができない既存のクラスに機能を追加したい時などに使うと思われる。

# 拡張メソッドの定義側サンプル

拡張メソッドの定義部分はこのような感じ。

```cs
using System.Collections.Generic;
using System.Linq;

namespace MyExtension
{
    public static class MyExtensionClass
    {
        /// <summary>
        /// int変数の累乗を求める
        /// </summary>
        public static int MyExp(this int me, int exp)
        {
            int ret = 1;

            for (int i = 0; i < exp; i++)
            {
                ret *= me;
            }

            return ret;
        }

        /// <summary>
        /// stringのリストを、一つのstringにつなげて出力する。
        /// </summary>
        public static string MyOutputListString(this List<string> strlist)
        {
            string ret = "";

            foreach (string s in strlist)
            {
                ret += s;
                ret += " ";
            }

            return $"{ret}以上の {strlist.Count()} 項目を拡張メソッドで出力しました。";
        }

        /// <summary>
        /// 文字列voiceをloop回数繰り返し、最後にendingを付加する
        /// </summary>
        public static string MyMakeOraora(this string voice, int loop, string ending)
        {
            string ret = "";

            for (int i = 0; i < loop; i++)
            {
                ret += voice;
            }

            return ret + ending;
        }
    }
}
```

### 拡張メソッドのルール
- staticなクラスの中に拡張メソッドを作る。
- 拡張メソッド自身もstaticにする。
- 引数の一つ目を「this 型 引数名」にする。
- その一つ目の引数が、拡張メソッドを使う値自身のことをさすことになる。
- 拡張メソッド内では、そのクラスのprivate変数にはアクセスできない。

# 拡張メソッド使用側サンプル
使う側は、このような感じになる。

```cs
using System;
using System.Collections.Generic;
using MyExtension; // 拡張メソッドのnamespaceを入れておく

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            // サンプル1個目
            int number = 5;
            Console.WriteLine("5の3乗は：" + number.MyExp(3));
            Console.WriteLine("11の2乗は：" + 11.MyExp(2));

            // サンプル2個目
            var slist = new List<string>();
            slist.Add("str1");
            slist.Add("str2");
            slist.Add("str3");
            Console.WriteLine(slist.MyOutputListString());

            // サンプル3個目
            Console.WriteLine("オラ".MyMakeOraora(10, "ァァァァァ！"));
            Console.WriteLine("アリ".MyMakeOraora(10, "アリーヴェデルチ！"));

            Console.ReadLine();
        }
    }
}

```

# 出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/b4e09308-cdd3-2c8e-1f17-3749217a94ea.png)

クラスや型の中身をいじらずに、簡単に機能を追加できた。

冒頭の「なんだこれ？」となったときのコードでは、UIの部品(UIElement)のクラスの見た目を、画像のクラスに変換するというときに、拡張メソッドで変換機能を追加してる感じだった。

- 画像クラス = UI部品.画像に変換メソッド();

のようなイメージ。

# 補足
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/61059a16-5e4c-9707-6094-e5337fd391da.png)

- 引数1個目は、「自分自身」のイメージ。使うときにはカッコの中ではなく前に出ている。
- 2つ目以降の引数は、通常通りカッコの中に引数を書く。



# LINQ
LINQは、実は拡張メソッド。

usingにSystem.Linqを入れていると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/e694a8ff-8fe7-ab9a-b905-912a50b142ca.png)
List等のうしろで「.」を打つと、「Where」等Linqで使うやつらがインテリセンスで出てくるが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/66a82bd6-630b-6b76-64a0-942960437745.png)
usingにLinqがないと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/fb5f8c9e-7fda-fb75-c09e-0d22e61141eb.png)
Whereが出てこないし、手で.Whereと打ったとしても使うことはできない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/eb0f2b61-442f-4fa0-6c70-23d450e8e5a2.png)

# 参考

https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/extension-methods