bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] Expression-Bodied メンバ・ローカル関数・static ローカル関数

[C#] Expression-Bodied メンバ・ローカル関数・static ローカル関数

Apr 9, 2026 C# , .NET bucket-sort

C# はバージョンを重ねるごとにメソッド関連の記述を改善する機能を追加してきました。本記事では Expression-Bodied メンバ(C# 6.0 〜)、ローカル関数(C# 7.0)、static ローカル関数(C# 8.0)の 3 つを整理します。

Expression-Bodied メンバ(C# 6.0 〜)

C# 6.0 で、メソッドや読み取り専用プロパティを => を使って 1 行で書ける Expression-Bodied 構文が導入されました。

// 従来の書き方
public int Add(int x, int y)
{
    return x + y;
}

// Expression-Bodied 構文(C# 6.0)
public int Add(int x, int y) => x + y;

return とブレースが不要になり、単純なメソッドをコンパクトに書けます。

対応範囲の拡張

C# 6.0 ではメソッドと読み取り専用プロパティのみに対応していましたが、C# 7.0 でコンストラクタ・デストラクタ・プロパティの get/set アクセサー・インデクサーにも拡張されました。

class Point
{
    public int X { get; }
    public int Y { get; }

    // コンストラクタ(C# 7.0)
    public Point(int x, int y) => (X, Y) = (x, y);

    // デストラクタ(C# 7.0)
    ~Point() => Console.WriteLine("破棄されました");

    // プロパティ get/set(C# 7.0)
    private int _value;
    public int Value
    {
        get => _value;
        set => _value = value;
    }

    // 読み取り専用プロパティ(C# 6.0)
    public string Label => $"({X}, {Y})";

    // メソッド(C# 6.0)
    public double Distance() => Math.Sqrt(X * X + Y * Y);
}

void メソッドへの適用

戻り値が void のメソッドにも使えます。

public void Print() => Console.WriteLine($"({X}, {Y})");

static メソッドへの適用

static メソッドでも同様に書けます。

public static int Max(int a, int b) => a > b ? a : b;

ローカル関数(C# 7.0)

C# 7.0 で、メソッドの中にメソッドを定義するローカル関数が導入されました。

public int Factorial(int n)
{
    return Calc(n);

    // ローカル関数(メソッド内に定義)
    int Calc(int x) => x <= 1 ? 1 : x * Calc(x - 1);
}

Calc は Factorial の中でのみ有効であり、外部からは呼び出せません。

ローカル関数の特徴

外側のスコープの変数にアクセスできる

public void Process(int[] data)
{
    int threshold = 10; // 外側の変数

    var result = data.Where(IsValid).ToArray();

    bool IsValid(int value) => value > threshold; // threshold を参照できる
}

引数検証と遅延実行の分離

イテレータや async メソッドは実行が遅延するため、引数の検証が即時に行われません。ローカル関数を使うとこれを解決できます。

// 公開メソッドで即時検証、ローカル関数でイテレータを実装
public IEnumerable<int> GetRange(int start, int count)
{
    if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));

    return Iterator();

    IEnumerable<int> Iterator()
    {
        for (int i = 0; i < count; i++)
            yield return start + i;
    }
}

再帰も書ける

public int Fibonacci(int n)
{
    return Fib(n);

    int Fib(int x) => x <= 1 ? x : Fib(x - 1) + Fib(x - 2);
}

Expression-Bodied との組み合わせ

ローカル関数にも Expression-Bodied 構文が使えます。

int Double(int x) => x * 2;

static ローカル関数(C# 8.0)

C# 8.0 では、ローカル関数に static 修飾子を付けられるようになりました。static ローカル関数は外側のスコープの変数やインスタンスメンバを参照できないことをコンパイラが保証します。

public int Process(int input)
{
    int factor = 3;

    return Compute(input);

    static int Compute(int x) => x * 2; // factor は参照不可
}

Compute 内で factor を参照しようとするとコンパイルエラーになります。

static ローカル関数のメリット

意図の明示
「この関数は外側の状態に依存しない」という意図をコードで表現できます。

クロージャの回避
通常のローカル関数が外側の変数をキャプチャすると、コンパイラは内部的にクロージャオブジェクトを生成します。static をつけることでキャプチャを禁止し、クロージャによるヒープ割り当てを防げます。

パラメータで必要な値を受け取る
外側の変数を使わない代わりに、必要な値は引数として渡します。

public double CalculateTotal(IEnumerable<decimal> prices, decimal taxRate)
{
    return prices.Sum(p => ApplyTax(p, taxRate));

    static decimal ApplyTax(decimal price, decimal rate) => price * (1 + rate);
}

通常のローカル関数 vs static ローカル関数

ローカル関数 static ローカル関数
導入バージョン C# 7.0 C# 8.0
外側の変数への参照 できる できない
this への参照 できる できない
クロージャの生成 キャプチャ時に発生 発生しない
意図の明示 依存関係が不明 純粋な関数であることが明確

まとめ

機能 導入 概要
Expression-Bodied メンバ(メソッド・プロパティ) C# 6.0 => で 1 行表記
Expression-Bodied メンバ(コンストラクタ等) C# 7.0 対応範囲を拡張
ローカル関数 C# 7.0 メソッド内に関数を定義、外側の変数を参照可
static ローカル関数 C# 8.0 外側の変数を参照しないことを保証

これらを適切に組み合わせることで、短く・読みやすく・意図が明確なコードを書けます。

C# .NET ラムダ式 ローカル関数 Expression-Bodied
← [C#] System.Range と .. 演算子 — コレクションの部分取得 [C#] メソッドパラメータの修飾子 — out / ref / in / params →

Related Posts

  • [C#] IEnumerable と IEnumerator — イテレータの仕組みと yield を使った実装 May 7, 2026
  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026

Table of Contents

  • Expression-Bodied メンバ(C# 6.0 〜)
    • 対応範囲の拡張
    • void メソッドへの適用
    • static メソッドへの適用
  • ローカル関数(C# 7.0)
    • ローカル関数の特徴
    • Expression-Bodied との組み合わせ
  • static ローカル関数(C# 8.0)
    • static ローカル関数のメリット
    • 通常のローカル関数 vs static ローカル関数
  • まとめ

Recent Posts

  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026
  • [C#] System.GC クラスを整理する — ガベージコレクションを制御するための API May 10, 2026
  • [C#] IComparable と IComparer — オブジェクトの順序比較と複数ソート戦略 May 9, 2026

Categories

  • C#63
  • .NET62
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • パフォーマンス
  • DoS
  • Nginx
  • Windows
  • WordPress
  • メモリ管理
  • 監視
  • 設計
  • Amazon Linux 2023
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • オブジェクト指向
  • クラス設計
  • コレクション
  • デザインパターン
  • パターンマッチング
  • 継承
  • 認可
  • Aurora
  • Blade
  • Grafana
  • Hugo
  • InfluxDB
  • Policy
  • Record
  • SSG
  • インターフェース
  • エラーハンドリング
  • カプセル化
  • ガベージコレクション
  • モニタリング
  • 例外
Powered by Hugo & Explore Theme.