ヘルパー ロジックにわかりやすい名前を付け、そのヘルパーが必要なメンバーは 1 つだけである場合は、ローカル関数を選択します。 含まれている型のメソッドと比較すると、ローカル関数はヘルパーがこの操作に属していることをリーダーに伝えます。 その名前を使用すると、閲覧者は詳細を調べる前に主な流れを把握することができます。
Tip
この記事では、メソッドの記述方法を知っている開発者向けのローカル関数の実用的な使用方法について説明します。 宣言の詳細と診断規則については、「 ローカル関数の宣言」を参照してください。
ローカル関数は、メソッドやコンストラクターなど、別のメンバー内で宣言された名前付き関数です。 その名前は、そのメンバー内でのみ有効です。
次の図は、ローカル関数を宣言して呼び出します。
string CreateMessage(string name)
{
return AddGreeting(name);
string AddGreeting(string value) => $"Hello, {value}!";
}
AddGreeting は CreateMessage内にとどまります。 型の他のメンバーはそれを呼び出すことはできません。
ヘルパーロジックを呼び出し元の近くに配置する
ローカル関数を使用すると、メインフローは何が起こるかを記述し、ヘルパー関数は個々のステップを説明します。 次の例では、読書プランを作成します。 ローカル関数を使用して、一度に 1 週間の割り当てを追加します。
IReadOnlyList<ReadingWeek> plan =
CreateReadingPlan("The Long Way Home", chapterCount: 10, chaptersPerWeek: 3);
foreach (ReadingWeek week in plan)
{
Console.WriteLine(
$"Week {week.Number}: {week.BookTitle}, chapters {week.FirstChapter}-{week.LastChapter}");
}
static IReadOnlyList<ReadingWeek> CreateReadingPlan(
string bookTitle,
int chapterCount,
int chaptersPerWeek)
{
var plan = new List<ReadingWeek>();
AddWeek(firstChapter: 1);
return plan;
void AddWeek(int firstChapter)
{
if (firstChapter > chapterCount)
{
return;
}
int lastChapter = Math.Min(
firstChapter + chaptersPerWeek - 1,
chapterCount);
plan.Add(new ReadingWeek(
plan.Count + 1,
bookTitle,
firstChapter,
lastChapter));
AddWeek(lastChapter + 1);
}
}
ReadingWeekは、週番号とその週に割り当てられた章の範囲を記録します。
AddWeek は CreateReadingPlanにのみ属しているため、そのローカル スコープはその関係を示します。
ローカル関数は、それを呼び出すステートメントの前または後に宣言できます。 コンテキストを失うことなく、読者がメイン フローに従うことができる場所に配置します。
パラメーターを使用するか、ローカル状態をキャプチャする
非静的ローカル関数は、その包含メンバーのパラメーターとローカル変数を使用できます。 この用途はキャプチャと呼ばれます。 読み取り計画の例では、AddWeek が取得する内容は次のとおりです。
-
chaptersPerWeekパラメーターからのbookTitle、chapterCount、およびCreateReadingPlan。 -
planをローカル変数から。
キャプチャは、ヘルパーが自然に周囲の操作に属している場合に便利です。 取得する値は少なく、分かりやすいものにしてください。 ヘルパーがパラメーターを介してすべてのデータを受け取ることができる場合は、 static ローカル関数を検討してください。
static int LastChapter(int firstChapter, int chaptersPerWeek, int chapterCount) =>
Math.Min(firstChapter + chaptersPerWeek - 1, chapterCount);
静的ローカル関数は、包含しているメンバーからローカル変数、パラメーター、またはインスタンスの状態をキャプチャできません。 そのパラメーターにより、指定されたデータが明示的になりますが、キャプチャではヘルパーがヘルパーを含む操作のコンテキストを使用できます。
問題が繰り返し現れる場合は、再帰を使用する
再帰は 、関数が問題の一部を小さくして自身を呼び出すときに発生します。
AddWeek この例では 1 週間を追加し、次の週の最初の項目で自分自身を呼び出します。
すべての再帰関数には、呼び出しを停止する条件が必要です。
AddWeekはfirstChapterがchapterCountを超えると停止します。
if (firstChapter > chapterCount)
{
return;
}
ローカル関数は、その名前は包含メンバー全体でスコープ内にあるため、再帰に適しています。 繰り返しの作業をより直接的に表現する場合は、ループを優先します。 再帰構造によってアルゴリズムの理解が容易になる場合は、再帰を選択します。
ローカル関数またはラムダ式を選択する
ローカル関数とラムダ式はどちらも周囲の変数を使用できますが、異なる意図を伝えます。
| Choose | When |
|---|---|
| ローカル関数 | ヘルパーは、名前を付ける利点がある場合、複数のステートメントがある場合、再帰が必要な場合、または包含メンバー内の複数の場所から呼び出される場合。 |
| ラムダ式 | 短い処理を別のメソッドに直接渡すか、デリゲート変数に格納します。 |
次のコードでは、両方の形式を使用します。
static IEnumerable<string> DescribeShortWeeks(
IEnumerable<ReadingWeek> plan,
int maximumChapters)
{
return plan
.Where(IsShortWeek)
.Select(week => $"Week {week.Number}: {week.FirstChapter}-{week.LastChapter}");
bool IsShortWeek(ReadingWeek week) =>
week.LastChapter - week.FirstChapter + 1 <= maximumChapters;
}
Console.WriteLine("Short weeks:");
foreach (string description in DescribeShortWeeks(plan, maximumChapters: 2))
{
Console.WriteLine(description);
}
IsShortWeek は、 Where に渡される規則にわかりやすい名前を付けます。
Selectに渡されたラムダは、その使用時に 1 つの短い変換を実行します。 両方とも、ここで別のメソッドに振る舞いを提供します。 ローカル関数は、読み取り計画の例での AddWeek のように、直接呼び出すヘルパーにすることもできます。
複数のメンバーがヘルパーを必要とする場合は、ローカル関数の代わりに通常のメソッドを使用します。 動作が短く、その目的が呼び出し先のメソッドから明確な場合は、代わりにラムダを使用します。
ローカル関数は、yield returnを含む反復子関数にすることもできます。 その用途については、「 反復子」を参照してください。
参照
.NET