- String クラスにバイト数が返してくれるメソッドが欲しい!
- DateTime 構造体に日付が含まれる月の最終日 (末日) を返してくれるメソッドが欲しい!!
- ICollection
インターフェースに指定した条件に一致するアイテムを削除してくれるメソッドが欲しい!!!
プログラミングを続けていると、とあるクラスや構造体などに「こんな処理をしてくれるメソッドがあったら便利なのにな~。」と思うことがよくあります。
それを自分で実現することができる仕組みが .NET には用意されています。
その名も「拡張メソッド」といいます。
.NET のバージョンアップとともに、メソッドが実装されることもないことはありませんが、自分で作った方が明らかに早いですから、この便利な仕組みを使っていきましょう。
拡張メソッドとは
拡張メソッドを使用すると、既存のクラスなどを変更して再コンパイルしたり、継承して派生クラスや派生インターフェースなどを作ることなく、既存のクラスなどに新たなメソッドを追加する (追加したように見せかける) ことができます。
つまり、冒頭の String クラスに文字列のバイト数を返してくれるメソッド LengthB メソッドを追加し
1 |
int length = "abdcefg".LengthB(); |
のように使うことができるようになります。
拡張メソッドの作り方
拡張メソッドを作る方法はとても簡単です。
以下の3つの規則を守ってメソッドを実装するだけです。
- 静的クラス (static class) を作る。
- 作った静的クラス内に静的メソッド (static Method) を作る。
- 静的メソッドの1つ目の引数には、メソッドを追加する型を this キーワードを付けて指定する。
拡張メソッドは、静的メソッドをインスタンスメソッドと同様の形式で呼び出すことができるようにしてくれる仕組みなのです。
では、上記の LengthB メソッドを題材に、拡張メソッドの作り方を見ていきましょう。
拡張メソッドの実装
拡張メソッドを作成していきます。
静的クラスの作成
静的クラスの定義は以下のようになります。
1 2 3 4 5 6 7 8 |
// 名前空間 namespace Extensions { // 静的クラス public static class StringExtension { } } |
ここでは namespace Extensions を作成し、そこに静的クラスの StringExtension という名前の静的クラスを作成しています。
静的メソッドの実装
静的メソッドは、作成した静的クラス内に作成します。
1 2 3 4 5 6 7 8 9 10 |
// 名前空間 namespace Extensions { // 静的クラス public static class StringExtension { // ここに静的メソッド (拡張メソッド) を作成します... public static int LengthB... } } |
ここでは StringExtension クラスに LengthB という名前で int の戻り値を返す静的メソッドを作成しようとしています。
静的メソッドの1つ目の引数には追加する型を this キーワードを付けて指定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 名前空間 namespace Extensions { // 静的クラス public static class StringExtension { // 静的メソッド (拡張メソッド) // 第1引数に this キーワードを付けた型を指定 public static int LengthB(this string str) { // ここに必要な処理を記述します... Encoding enc = Encoding.GetEnc... } } } |
ここまでで、拡張メソッドはほぼ完成です。
では、残りを実装した完成コードを記載します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 名前空間 namespace Extensions { // 静的クラス public static class StringExtension { // 静的メソッド (拡張メソッド) // 第1引数に this キーワードを付けた型を指定します。 public static int LengthB(this string str) { // エンコードを Shift_JIS に変換します。 Encoding enc = Encoding.GetEncoding("Shift_JIS"); // エンコードからバイト数を取得します。 int length = enc.GetByteCount(value); // 取得したバイト数を返します。 return length; } } } |
上記の例では、引数が拡張メソッドを追加する型のみになっていますが、第2引数以降には通常のメソッドと同様にメソッドで使用する引数を指定することができます。
1 2 3 4 5 |
// 名前空間 public static SomeTypeA SomeMethod(this SomeTypeB target, SomeTypeC argument1, SomeTypeD argument2...) { // メソッド内の処理を記述します... } |
拡張メソッドの使用
拡張メソッドを使用する側では、拡張メソッドを実装したクラスの名前空間 (namespace) を using (インポート) します。
上記の例では Extensions という名前空間を作成したので以下のようにします。
1 |
using Extensions; |
これで拡張メソッドが使えるようになったので、作成したメソッドを呼び出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System; // 作成した拡張メソッドのクラスの名前空間をインポート using Extensions; namespace ConsoleApp1 { class Program { static void Main(string[] args) { string str = "あいうえお"; // 作成した拡張メソッドを string クラスの // インスタンスメソッドとして呼び出します。 int length = str.LengthB(); // コンソールに出力します。 Console.WriteLine($"あいうえおのバイト数は {length} です。"); } } } |
拡張メソッドはインターフェースや構造体にも作成できます。また、ジェネリックな型に対しても作成が可能です。
拡張メソッドを使いこなすことができると実装の幅が広がります。
皆さんも是非、拡張メソッドを色々と作ってみてください。