メソッドの理解とC#拡張メソッドの使用
C# プログラミングでは、メソッドは再利用可能なコードをカプセル化し、特定のタスクを実行する重要なビルディングブロックです。 これらの開発ツールは、パラメータを受け取り、値を返し、さまざまな入力を処理するためにオーバーロードすることができます。 より高度な概念である拡張メソッドは、開発者が制御していない型も含め、既存の型に機能を追加することを可能にします。
ティム・コリーのビデオ"C#で拡張メソッドを作成する方法"は優れたリソースです。 このガイドでは、Timがカバーするいくつかのトピックを探ります:
1.メソッドの定義と呼び出し 2.メソッドのパラメータと引数 3.メソッドの戻り値 4.メソッドのオーバーロード 5.Extensionメソッドの実装
メソッドの定義と呼び出し
インスタンスメソッドの定義
C#では、メソッドはクラス内で定義されます。 メソッド定義の一般的な構文には、アクセス修飾子、戻り値型、メソッド名、パラメータが含まれます。
public class SampleClass
{
public void SampleMethod()
{
// Method implementation
}
}public class SampleClass
{
public void SampleMethod()
{
// Method implementation
}
}Tim Coreyの4:05の例では、彼は静的クラス内でメソッドを定義し、拡張メソッドを作成している。 定義されたメソッドはPrintToConsoleです。 定義には一般的な構文がすべて含まれ、実用的な例を用いてメソッドの定義方法を明確に説明します:
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}メソッドの呼び出し
メソッドコール"は、コード内の別の場所に定義された特定のメソッドを実行し、事前に定義されたアクションを実行するようプログラムに指示します。 メソッドは、クラスのインスタンスを使用して呼び出されるか、静的メソッドの場合は直接呼び出されます。 拡張メソッドについては、拡張する型の一部であるかのように表示されます。 6:18のビデオでは、Timが、定義済みのメソッドと同じように、プリミティブなデータ型で拡張メソッドを呼び出す方法を示しています。
string demo = "This is a demo";
demo.PrintToConsole(); // Extension method callstring demo = "This is a demo";
demo.PrintToConsole(); // Extension method callメソッドのパラメータと引数
パラメーター
パラメータはメソッド定義で指定され、メソッドに渡される値のプレースホルダとして機能します。 ここで、messageがパラメータであることがわかります。
public void DisplayMessage(string message)
{
Console.WriteLine(message);
}public void DisplayMessage(string message)
{
Console.WriteLine(message);
}再び、4:05にティム・コーリーが挙げた拡張メソッドの例では、messageがパラメータです。
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}論拠
引数は、メソッドが呼び出されたときに渡される実際の値です。
DisplayMessage("Hello, World!"); // "Hello, World!" is the argumentDisplayMessage("Hello, World!"); // "Hello, World!" is the argumentティム・コーリーが6:20にドット構文を使用して文字列タイプでメソッドを呼び出す際、実際には文字列値がPrintToConsoleメソッドに値として渡されます。
string demo = "This is a demo";
demo.PrintToConsole(); // "This is a demo" is the argumentstring demo = "This is a demo";
demo.PrintToConsole(); // "This is a demo" is the argumentメソッドの戻り値
メソッドは return 文を使って値を返すことができます。 戻り値の型は、メソッドのシグネチャで指定します。
public int Add(int a, int b)
{
return a + b;
}public int Add(int a, int b)
{
return a + b;
}Tim Coreyのビデオに登場する拡張メソッドは値を返しませんが(void戻り値型)、戻り値を持つ拡張メソッドを作成することができます。 Tim の例の戻り値の型は void で、これはメソッドが値を返さないことを意味します。 次の例は、値を返す方法を示しています:
public static int WordCount(this string str)
{
return str.Split(' ').Length;
}public static int WordCount(this string str)
{
return str.Split(' ').Length;
}メソッドのオーバーローディング (11:15)
メソッドのオーバーロードは、複数のメソッドが同じ名前で異なるパラメータを持つことを可能にします。 これは、柔軟で直感的なAPIの作成に役立ちます。
public void Display(string message)
{
Console.WriteLine(message);
}
public void Display(int number)
{
Console.WriteLine(number);
}public void Display(string message)
{
Console.WriteLine(message);
}
public void Display(int number)
{
Console.WriteLine(number);
}ティム・コリーは、11:24で異なるロギングシナリオのために複数のメソッドを作成することについて簡単に触れていますが、これは広い意味でのメソッドのオーバーロードの例として見ることができます。 logメソッドは、1つのパラメータを持つものと2つのパラメータを持つものの2つ存在します。 11:39の2番目のログメソッドは、ログメソッドのオーバーロード版で、同じ名前で複数の機能を与えている。
Implementing Extension Methods in C
拡張メソッドとは何ですか? (3:13)
拡張メソッドを使用すると、既存の型を変更したり再コンパイルしたりすることなく、既存の型に新しいメソッドを追加できます。 拡張メソッドはインスタンスメソッドのように呼ばれますが、静的メソッドとして定義されます。
拡張メソッドの作成
前のセクション"メソッドの定義と呼び出し"では、ティム・コリーが別の静的クラスで拡張メソッドを作成し、その中で静的メソッドを定義して拡張メソッドとして使用する方法を紹介しました。 以下は、ティム・コーリーが強調するポイントです:
1.必ず別のpublic staticクラスを定義するか、ティムが言うように、"staticとマークしないと動作しません"。 2.より多くの拡張メソッドを作成したら、それらをタイプ別にグループ化する(3:43)
- 最初のパラメータを
thisキーワードで接頭辞として定義し、拡張する型を指定する静的メソッドを定義します (4:58)
public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}public static class Extensions
{
public static void PrintToConsole(this string message)
{
Console.WriteLine(message);
}
}拡張メソッドの呼び出し (6:18)
次に、Tim はこの文字列変数で拡張メソッドを呼び出す方法を示します:
demo.PrintToConsole();demo.PrintToConsole();PrintToConsoleメソッドを提案します。 これはstring型に追加された新しいメソッドです。
メソッド呼び出しの仕組み (6:30)
ティムはなぜdemo.PrintToConsole()を呼び出すことができるのかを説明します:
- デモは文字列型です: 変数
string型です。 - 拡張された文字列型:
PrintToConsoleで拡張されました。
パラメータの理解 (6:41)
PrintToConsoleメソッドにはパラメータが渡されていないように見えますが、ティムは暗黙のパラメータ渡しを指摘します - demo文字列が拡張メソッドへの最初のパラメータとして渡されます。
Timは、拡張メソッドは、定義よりも呼び出しのパラメータが1つ少ないことを強調しています。 これは、最初のパラメータ(拡張される型)が暗黙的であるためです。
拡張メソッドの署名
ここでmessageが暗黙のパラメータです:
public static void PrintToConsole(this string message)public static void PrintToConsole(this string message)コードの実行 (7:08)
最後に、PrintToConsoleメソッドが呼び出されると、文字列がコンソールに出力されます:
Console.WriteLine(message);Console.WriteLine(message);そのため、demo.PrintToConsole()を呼び出すと、"This is a demo"がコンソールに表示されます。
サードパーティ製クラスの拡張メソッドを使用する
サードパーティ製クラスの拡張 (10:59)
ティム・コリーは、拡張メソッドは、直接変更できないサードパーティのクラスであっても、あらゆる型を拡張できると説明しています。 たとえば、11:09にSimpleLoggerクラスを見てみましょう。
ここで、ティムはメッセージをコンソールに記録する仮想のサードパーティークラスSimpleLoggerを使用しています(11:09)。 このクラスには2つのメソッドがあります:
public class SimpleLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
public void Log(string message, string messageType)
{
Console.WriteLine($"{messageType}: {message}");
}
}public class SimpleLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
public void Log(string message, string messageType)
{
Console.WriteLine($"{messageType}: {message}");
}
}メッセージタイプが単純な文字列であるため、矛盾が生じる可能性があり、これらの方法は理想的ではありません。 Timは、クラスを改善するために拡張メソッドを作成することを提案します。
一貫したメッセージ型の実装
拡張メソッドを使用すると、常に同じメッセージタイプと書式を使用することにより、コードの一貫性が保証されます。 ここで(12:40に)ティムは静的クラスExtendSimpleLoggerを作成します:
public static class ExtendSimpleLogger
{
public static void LogError(this SimpleLogger logger, string message)
{
logger.Log(message, "Error");
}
public static void LogWarning(this SimpleLogger logger, string message)
{
logger.Log(message, "Warning");
}
}public static class ExtendSimpleLogger
{
public static void LogError(this SimpleLogger logger, string message)
{
logger.Log(message, "Error");
}
public static void LogWarning(this SimpleLogger logger, string message)
{
logger.Log(message, "Warning");
}
}コールをより一貫したものにする
それを手に入れることで、(14:02に)彼はSimpleLoggerインスタンス上で拡張メソッドを呼び出すことができるようになりました:
SimpleLogger logger = new SimpleLogger();
logger.LogError("This is an error");
logger.LogWarning("This is a warning");SimpleLogger logger = new SimpleLogger();
logger.LogError("This is an error");
logger.LogWarning("This is a warning");このため、メッセージタイプは常に"エラー"と"警告"であることが保証されます。
出力フォーマットの強化 (14:35)
Timは、エラーメッセージのコンソールテキストの色を設定する機能を追加し、目立つようにしました:
public static void LogError(this SimpleLogger logger, string message)
{
var defaultColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
logger.Log(message, "Error");
Console.ForegroundColor = defaultColor;
}public static void LogError(this SimpleLogger logger, string message)
{
var defaultColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
logger.Log(message, "Error");
Console.ForegroundColor = defaultColor;
}直接メソッド呼び出しとの比較 (17:21)
ティムは、このアプローチをオリジナルのLogメソッドを直接呼び出すのと比較し、不一致を引き起こす可能性があることを示しています:
logger.Log("Test error", "Error");
logger.Log("Another error", "ERROR");logger.Log("Test error", "Error");
logger.Log("Another error", "ERROR");このアプローチでは、誤字や一貫性のない書式が発生しがちです。
拡張メソッドのチェーン (18:13)
Timは、コードをより読みやすくするために、拡張メソッドをどのように連鎖させることができるかを示します:
public static void LogInfo(this SimpleLogger logger, string message)
{
logger.Log(message, "Info");
}
public static void SaveToDatabase(this SimpleLogger logger)
{
// Simulate saving to a database
}public static void LogInfo(this SimpleLogger logger, string message)
{
logger.Log(message, "Info");
}
public static void SaveToDatabase(this SimpleLogger logger)
{
// Simulate saving to a database
}今、あなたはこれらの方法を連鎖させることができます:
logger.LogInfo("Information").SaveToDatabase();logger.LogInfo("Information").SaveToDatabase();これにより、ネストされたメソッド呼び出しに比べて、コードがより読みやすく、直感的になります:
SaveToDatabase(LogInfo(logger, "Information"));SaveToDatabase(LogInfo(logger, "Information"));ドット表記とチェーニングを使用することで、コードの意図が明確になり、入れ子が少なくなります。
所有していないものを拡張する
20:13で、ティム・コーリーは、拡張メソッドは、サードパーティのライブラリなど、自分が所有していないクラスに機能を追加するのに理想的であると説明している。 これにより、元のコードを修正することなく、機能拡張を行うことができます。
依存関係の回避
また、Corey は、クラスに直接カップリングすることなく依存関係を導入するための拡張メソッドの使用についても強調しています。 たとえば、データベースのロジックを埋め込まずにデータベースの保存機能をPersonクラスに追加すること。
インターフェイスの拡張
21:30から説明されるように、拡張メソッドはインターフェースにも適用でき、インターフェースを実装した複数のクラスが同じ機能を共有することを可能にする。 これにより、コードの再利用と簡素化が促進されます。
拡張メソッドを使用しない場合
23:03で、ティム・コーリーは、特にプリミティブ型やマイクロソフトが提供する型では、乱雑さと複雑さを防ぐために、拡張メソッドを使いすぎないようにアドバイスしている。 これらのツールの使用は控えめにし、明確な利点がある場合にのみ使用してください。
オープン/クローズの原則
24:54-25:40のセクションでは、Timは、既存の安定したコードを変更することなく、新しい機能を追加するために拡張メソッドを使用することにより、バグをもたらすリスクを低減し、オープン/クローズの原則を遵守することを強調しています。
ステートメントを使用するためのベストプラクティス
拡張メソッドを論理的にグループ化し、別々の名前空間に配置することで、名前の衝突を避け、メンテナンスとデバッグを容易にします。
結論
これで、メソッドの定義と呼び出し、パラメータと戻り値の処理、メソッドのオーバーロードの活用の基本を理解したことになります。 これにより、C#で堅牢かつ柔軟なアプリケーションを構築することができます。
ティム・コリーが説明する拡張メソッドは、既存の型を拡張し、コードをより読みやすく保守しやすくする強力な方法を提供します。 より詳細な洞察と実用的な例については、How To Create Extension Methods in C# に関するティム・コーリーのビデオ全編をご覧ください。

