C Sharpの基礎 - 拡張メソッド

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
2024年1月21日 (日) 15:47時点におけるWiki (トーク | 投稿記録)による版 (→‎拡張メソッドの使用)
ナビゲーションに移動 検索に移動

概要

C#において、独自の拡張メソッドを実装する手順を記載する。

拡張メソッドを使用するには、usingディレクティブを使用して、拡張メソッドが定義されている名前空間を指定する。


拡張メソッドの実装

  1. 拡張メソッドを実装するための静的クラスを定義する。
    この静的クラスは、クライアントコードから参照できる必要がある。
  2. 拡張メソッドを静的メソッドとして実装する。
  3. メソッドの最初の引数では、操作する型を指定する。
    型名の前には、this修飾子を付加する。


名前の衝突において、呼び出し元のクラスで定義されているメソッドが優先されるため、拡張メソッドが使用されることはない。


拡張メソッドの使用

  1. 呼び出し元において、usingディレクティブを使用して、拡張メソッドの静的クラスを含む名前空間を指定する。
  2. クラスのインスタンスメソッドと同様にメソッドを記述する。
    呼び出し元では、最初の引数は指定しない。
    これは、演算子を適用する型を表すものであり、コンパイラはオブジェクトの型を既に認識しているためである。
    指定する必要があるのは、第2引数以降の引数のみである。


静的クラスに静的メソッドを定義して、その第1引数の前にthisキーワードを付加する時、拡張メソッドになる。
第1引数の型が、拡張される対象となる。

整数型

以下の例では、拡張メソッドAddは、int型を拡張している。(第1引数のthis int)
拡張メソッドに第2引数を指定する時、拡張メソッドの第1引数として渡される。

つまり、拡張メソッドに引数を付加して呼び出す場合、その引数は拡張メソッドの第2引数以降として渡される。

 using System;
 
 namespace SampleNamespace
 {
    public static class SampleExtension
    {
       public static int Add(this int m, int n) => m + n;
    }
 }


 using System;
 using SampleNamespace;  // 拡張メソッドを定義している名前空間
 
 class Program
 {
    static void Main(string[] args)
    {
       int m = 2;
 
       int result = m.Add(3);
 
       // また、通常の静的メソッドとして、SampleExtension.Add(m, 3)のように呼び出すことも可能である
       // SampleExtension.Add(m, 3)
 
       // 定数リテラルでも拡張メソッドを使用することができる
       // int result = 2.Add(3);  出力 : 5
 
       Console.WriteLine($"m.Add(3) : {result}");  // 出力 : 5
    }
 }


文字列型

以下の例では、CustomExtensions名前空間のStringExtensionクラスを作成して、WordCount拡張メソッドを実装している。
この拡張メソッドは、第1引数で指定したStringクラスを操作する。

 using System.Linq;
 using System.Text;
 using System;
 
 namespace CustomExtensions
 {
    // Extension methods must be defined in a static class.
    public static class StringExtension
    {
       // This is the extension method.
       // The first parameter takes the "this" modifier
       // and specifies the type for which the method is defined.
       public static int WordCount(this String str)
       {
          return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
       }
    }
 }


 // Import the extension method namespace.
 using CustomExtensions;
 
 namespace Extension_Methods_Simple
 {
    class Program
    {
       static void Main(string[] args)
       {
          string s = "The quick brown fox jumped over the lazy dog.";
          // Call the method as if it were an
          // instance method on the type. Note that the first
          // parameter is not specified by the calling code.
          int i = s.WordCount();
          System.Console.WriteLine("Word count of s is {0}", i);
       }
    }
 }


インタフェースおよびジェネリック

インタフェースおよびジェネリックに対しても拡張メソッドも作成することができる。
C#のインタフェースはデフォルトの実装を持つことはできないが、それに近いことが可能である。

 public static bool IsGreaterThan<T>(this IComparable<T> m, T n) where T : struct => (0 < m.CompareTo(n));


 // 使用例
 
 Console.WriteLine($"{2.IsGreaterThan(3)}");       // 出力:False
 Console.WriteLine($"{2.5.IsGreaterThan(2.5)}");   // 出力:False
 Console.WriteLine($"{2.7d.IsGreaterThan(2.5d)}"); // 出力:True
 Console.WriteLine($"{(new DateTime(2017, 11, 15)).IsGreaterThan(new DateTime(2017, 11, 14))}");


メソッドチェーン

メソッドチェーンとは、メソッドを鎖のように続けて記述することである。
例えば、LINQでは <プロパティ名>.Where(/* 処理 1 */).Select(/* 処理 2 */) のようにメソッドを繋げて記述することができる。

以下の例では、拡張メソッドAddと拡張メソッドMultiplyを定義する場合、メソッドチェーンが使用できる。

 // 拡張メソッド
 
 public static int Add(this int m, int n) => m + n;
 
 public static int Multiply(this int m, int n) => m * n;


 // 使用例
 
 int result = 2.Add(3).Multiply(4);
 Console.WriteLine($"2.Add(3).Multiply(4)→{result}");  // 出力 : 20