
みなさんこんにちは! ガノー(Ganohr)です! (≧▽≦)
最近Lancers経由のIT系記事の執筆や、WordPressのカスタマイズや不具合対応の依頼が多く舞い込んでおり、忙しい生活を送っております。
しかし、Lancersではある建設業者を名乗る、非常に悪質なクライアントにより脅迫被害が2か月以上続いており、距離を置かなければならないかと感じています。
そんな愚痴はともかく、C#ビギナーの方に是非とも覚えていただきたい技術が「メソッドチェーン」です。
そこで今回は、
- メソッドチェーンとはなにか
- メソッドチェーンの定義サンプル
- メソッドチェーンの利点
を解説します!
更新履歴
2022/01/18 軽微な修正
2020/12/24 公開
メソッドチェーンとは何か?
‘メソッドチェーン’(Method Chain)とは「セッター」(Setter:値を設定するメソッド)や「サブルーチン」(Sub-routine:関数)などの、本来は戻り値の不要なメソッドにおいても、処理を行う「インスタンス」(Instance、処理を行っている実態)を返却することで、処理を「.」(ドット演算子)で列記していけるコーディングスタイルです。
メソッドチェーンは特に新しい記述方法ではありませんが、一度コーディングしてしまえばそれ以降楽にプログラミングできるようになります。
そのため、多くのプログラマーに支持されているコーディングスタイルです。
メソッドチェーンのサンプルコード
using System;
namespace CSharpHowToUseMethodChain
{
class Program
{
// メソッドチェーン未使用
class A
{
public A()
{
Console.WriteLine("A");
}
public void Init()
{
Console.WriteLine("Init");
// いわゆるサブルーチン(void function)では戻り値はない
}
public void Run()
{
Console.WriteLine("Run");
// いわゆるサブルーチン(void function)では戻り値はない
}
}
// メソッドチェーン使用例
class B
{
public B()
{
Console.WriteLine("B");
}
public B Init()
{
Console.WriteLine("Init");
return this; // メソッドチェーンでは自身のインスタンスを返す
}
public B Run()
{
Console.WriteLine("Run");
return this; // メソッドチェーンでは自身のインスタンスを返す
}
}
static void Main(string[] args)
{
// メソッドチェーン未使用だと定義毎にインスタンス指定が必要
var a = new A();
a.Init();
a.Run();
// メソッドチェーンなら、インスタンス指定が不要になる
new B().Init().Run();
}
}
}
A
Init
Run
B
Init
Run
クラスAはメソッドチェーンを使わずに定義したクラスであり、対してBはメソッドチェーンを利用しています。
この例では「初期化処理」(Init
)を行った後に、「実行」(Run
)せねばなりません。
クラスAは、「インスタンスの生成」(new
)と初期化処理に加え、実行までの呼び出しに3行もの記述が必要です。加えて、「a.~」という風に、使用するインスタンスを毎回指定せねばなりません。
しかしBクラスのようにメソッドチェーンを用いるとこれらの定義が簡便に行えます。メソッドチェーンを用いれば、「逐次的な処理」を「.
」(ドット演算子)で繋げて記述できるのです。
このように記述できる理由は、関数の戻り値をvoid
とするのではなく、そのクラス(のインスタンス)自体を返却していることです。
メソッドチェーンの3つの利点(概要)
メソッドチェーンは大まかに分けて3つの利点があります。
- 無駄なインスタンス指定が減るためコーディングが楽になる
- メソッドチェーンは言語の壁はなく、様々な言語で利用できる
- メソッドチェーンを理解しておくと、LINQへの理解につながる
メソッドチェーンの利点1:無駄なインスタンス指定が減るためコーディングが楽になる
メソッドチェーンはコーディング量を減らせる明確な利点があります。これは先述の例を読んでいる方なら理解できるでしょう。
実際に文字数で比較した場合「29」文字→「20」文字となり、明らかにコーディング量が減っています。これがより大きなプロジェクトになれば、もっと明確に差が開きます。
var a = new A();
a.Init();
a.Run();
※ 29文字、改行含まず
new B().Init().Run();
※ 20文字、改行含まず
メソッドチェーンの利点2:メソッドチェーンは言語の壁はなく、様々な言語で利用できる
メソッドチェーンは、プログラミング言語に依存する技術ではありません。メソッドチェーンはC#だけでなく、Javaはもちろん、Objective-Cに、C++などの様々な言語で実現できます。
この技術は「オブジェクト指向プログラミング」(Object-Oriented Programming)であれば実現できます。メソッドチェーンはいわゆる「インスタンス化」(Instancing)と「カプセル化」(Encapsulation)によって実現される技術です。
したがってJavaScriptやLuaに、更にはC言語(C99以降)でも実現できます。
メソッドチェーンの利点3:メソッドチェーンを理解しておくと、LINQへの理解につながる
メソッドチェーンは、LINQの機関技術になっています。そもそも‘LINQ’(Language INtegrated Query、統合言語クエリ、リンク)とは、データの集合を操作するための、C#3.0より利用可能な機能です。
LINQはメソッドチェーンで実現されており、その記述の「糖衣構文」(とういこうぶん)を定義したものです。糖衣構文とは、面倒な記述を減らすための特別な構文です。
例えば以下のコードはLINQを用いて、「1~3」の範囲の整数の配列(1,2,3)から2以上のdataを抽出する例です。
var n = from d in Enumerate.Range(1,3)
where d >= 2
select d;
このコードは簡潔ですが、正しく理解するためにはメソッドチェーンへの理解が必要です。なぜならこの例は、コンパイル時に以下のような内容に変換されるためです。
※ 変数名などは解説用に仮のものを採用しています。
var n = Enumerate.Range(1,3)
.Where(d=>d >= 2)
.Select(d=>d);
※ この例では、Selectメソッドの呼び出しは省略できますが、説明用に記述しています。
このように、メソッドチェーンを理解していれば、
- なぜLINQの記述においてまず
from
句を書くのか - なぜ
where
句の方がselect
句より先なのか
といったことが理解できるでしょう。
メソッドチェーンの唯一の欠点
メソッドチェーンは、唯一の欠点があります。
それは「コーディングスタイルにより見易さが依存する」という点です。
現在、ソースコードは肥大化の一途を辿っています。クライアント要望の多様化による高機能化はもちろん、ソースコードを横ではなく縦に長くするスタイルが支持されていることなど要因は様々です。
そのような状況下では、ドット演算子に依存したメソッドチェーンはコーディングスタイルによって、見易さに雲泥の差が生まれてしまいます。
基本的にメソッドチェーンは、「あくまでも同一のインスタンスを逐次的に処理しているだけ」ですので、ドット演算子の位置は揃えるべきです。
しかしオートフォーマットの設定によっては、行頭のドット演算子毎にインデントを下げてしまうものがあります。
これは別のインスタンスを処理する場合には適切ですが、同一のインスタンスを用いたメソッドチェーンにおいては不適切です。
↓ 悪い例(同一インスタンスなのにインデントを下げ続ける必要はない)
new B()
.Init()
.Run();
↓ 良い例(同一インスタンスはインデントを揃える)
new B()
.Init()
.Run();
このように、メソッドチェーンの唯一の欠点は「採用するオートフォーマットによりコーディングスタイルが依存する」ということが理解できるでしょう。
最後に
今回解説したメソッドチェーンは、そこまで新しい技術ではありません。
しかし、多くのプログラマーに支持されているコーディングスタイルにもかかわらず、この技術を知らない方も往々にしています。
プログラマーとして活躍されている・活躍していく皆さんが、今回紹介した便利で且つLINQなどの基幹として採用されている技術を正しく理解できるよう、今回の記事が参考になれば幸いです。
コメントを書く