C#

【C#】式形式のメンバー(式本体の定義)

この記事では式形式のメンバーについて解説します。

式形式のメンバーとは

式形式のメンバーは、英語ではExpression-bodied membersとなっています。これはラムダ演算子=>を使ってラムダ式ライクに簡潔にメンバーの実装を記述する方法です。式本体の定義(Expression body definitions)とも言います。この記述方法が使用できるメンバーは、

  • メソッド (C# 6)
  • 読み取り専用プロパティ (C# 6)
  • プロパティ (C# 7.0)
  • コンストラクタ (C# 7.0)
  • ファイナライザ (C# 7.0)
  • インデクサ (C# 7.0)

です。
…といっても何のことやらわかりませんので、実際にコードを確認しながら見ていきましょう。

なお、ラムダ式ライクと言っても、その前にラムダ式がよくわからない…という方は、コチラもぜひ参考にしてください。

式形式のメソッド

まずは式形式のメソッドについて説明していきます。まずは下記のコードを見てみましょう。

コード

using System;

internal class Program
{
    static void Main(string[] args)
    {
        int c = 10;
        Console.WriteLine("{0}の2倍にすると{1}です(ToDblAを使用)", c, ToDblA(c));
        Console.WriteLine("{0}の2倍にすると{1}です(ToDblBを使用)", c, ToDblB(c));
    }

    static int ToDblA(int x)
    {
        return 2 * x;
    }

    static int ToDblB(int x) => 2 * x;
}

出力結果

10の2倍にすると20です(ToDblAを使用)
10の2倍にすると20です(ToDblBを使用)

上記コードのToDblAは見ての通り引数の値を2倍にして返すメソッドです。式形式のメソッドでは、ToDblAと同じ処理をToDblBのように表すことができます。=>以降にメソッドの戻り値を記述します。この書き方は式形式のラムダ式の記述に似ていませんか?

この表現ができるのは、=>演算子の後ろが、戻り値の場合だけです。式形式のラムダ式と同様にreturnキーワードも不要です(むしろ書いてはいけません)。また、例えば2行以上の及ぶ処理の場合は=>演算子は使えません。2行以上の場合には普通にメソッドを書けばいいです。このあたりは式形式のラムダと同じ感じですね。

式形式の読み取り専用プロパティ

次は読み取り専用プロパティを式形式で表現します。

通常の読み取り専用プロパティは下記のように書きます。

public 型名 プロパティ名
{
  get{ return フィールド名; }
}

上記のように読み取り専用プロパティのgetアクセッサをひとつのステートメントで書けるとき、式形式で読み取り専用プロパティを書くことができます。式形式の読み取り専用プロパティは下記のようになります。

public 型名 プロパティ名 => フィールド名;

それではコードを見てみましょう。

コード

using System;

internal class Program
{
    static void Main(string[] args)
    {
        Person psn = new Person("太郎", 17, 170);
        Console.WriteLine("名前は{0}, 年齢は{1}歳, 身長は{2}cmです", psn.Name, psn.Age, psn.Length);
    }
}

internal class Person
{
    string name;
    int age;
    double length;

    public Person(string _name, int _age, double _length)
    {
        this.name = _name;
        this.age = _age;
        this.length = _length;
    }

    //読み取り専用プロパティ
    public string Name => name;
    public int Age => age;
    public double Length => length;
}

出力結果

名前は太郎, 年齢は17歳, 身長は170cmです

上記コードの26~28行目が式形式の読み取り専用プロパティです。式形式の読み取り専用プロパティでは=>を使うことでgetやreturnを省略して簡潔に書くことができます。
26~28行目の記述は下記のコードとまったく同じ意味です。

    public string Name
    {
        get { return name; }
    }
    public int Age
    {
        get { return age; }
    }
    public double Length
    {
        get { return length; }
    }

式形式のプロパティ

次にプロパティを式形式を利用してget,setアクセッサを実装します。

get,setアクセッサによるプロパティは通常は下記のようになります。

public 型名 プロパティ名
{
  get { return フィールド名;}
  set { フィールド名 = value;}
}

上記のようにget,setをそれぞれひとつのステートメントで書けるときには、プロパティを式形式で下記のように書くことができます。

public 型名 プロパティ名
{
  get => フィールド名;
  set => フィールド名 = value;
}

それでは例を見てみましょう。

コード

using System;

internal class Program
{
    static void Main(string[] args)
    {
        Person psn = new Person("太郎", 17);
        psn.Age++;
        Console.WriteLine("名前は{0}, 年齢は{1}歳です", psn.Name, psn.Age);
    }
}

internal class Person
{
    string name;
    int age;

    public Person(string _name, int _age)
    {
        this.name = _name;
        this.age = _age;
    }

    //プロパティ
    public string Name
    {
        get => name;
        set => name = value;
    }
    public int Age
    {
        get => age;
        set => age = value;
    }
}

出力結果

名前は太郎, 年齢は18歳です

上記のコードのとおり、25~34行目が式形式のプロパティになっています。
上記25~34行目のコードは下記コードと同じです。

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    public int Age
    {
        get { return age; }
        set { age = value; }
    }

式形式のコンストラクタ

コンストラクタを一つのステートメントで実装できる時には、式形式が使用できます。
引数が一つのコンストラクタは、通常、下記のように書きます。

public クラス名(型名 変数名)
{
  フィールド名 = 変数名;
}

上記のコンストラクタを式形式では下記のように書きます。

public クラス名(型名 変数名) => フィールド名 = 変数名;

それでは例をみてみましょう。

コード

using System;

internal class Program
{
    static void Main(string[] args)
    {
        Person psn = new Person("太郎");
        psn.age++;
        Console.WriteLine("名前は{0}, 年齢は{1}歳です", psn.name, psn.age);
    }
}

internal class Person
{
    public string name;
    public int age = 0;

    //コンストラクタ
    public Person(string _name) => this.name = _name;
}

出力結果

名前は太郎, 年齢は1歳です

上記コードの19行目がコンストラクタです。通常、コンスタラクタでは一つのフィールドに対して一つの引数が割り当てられますので、式形式で書く場合のコンストラクタの引数は1つです。2つ以上だと複数のステートメントが必要になるため、式形式は使用できません。

式形式のファイナライザ

ファイナライザ(以前はデストラクタと呼ばれてた)も式形式で実装することができます。

通常、ファイナライザは次のような構文になります。

~クラス名()
{
  実行したい処理;
}

上記のファイナライザを式形式で表すと次のようになります。

~クラス名() => 実行したい処理;

それでは例を見てみましょう。

コード

using System;

internal class Program
{
    static void Main(string[] args)
    {
        Test();

        GC.Collect(); //ガベージコレクション実行
    } 

    static void Test()
    {
        Person psn = new Person("太郎");
        psn.age++;
        Console.WriteLine("名前は{0}, 年齢は{1}歳です", psn.name, psn.age);
    }
}

internal class Person
{
    public string name;
    public int age = 0;

    //コンストラクタ
    public Person(string _name) => this.name = _name;

    //ファイナライザ
    ~Person() => Console.WriteLine("{0}さんのファイナライザを呼び出しました",name);
}

出力結果

名前は太郎, 年齢は1歳です
太郎さんのファイナライザを呼び出しました

上記コードでは9行目でガベージコレクションを実行して29行目のファイナライザを呼び出しています。

式形式のインデクサ

インデクサも式形式で書くことができます。

インデクサは通常、下記のように書きます。

public 型名 this[int index]
{
  get { return 変数名[index]; }
  set { 変数名[index] = value; }
}

上記のインデクサを式形式で書くと下記のようになります。式形式のプロパティと似ています。

public 型名 this[int index]
{
  get => 変数名[index];
  set => 変数名[index] = value;
}

それでは例を見ていきましょう。

コード

using System;
using System.Collections.Generic;

internal class Program
{
    static void Main(string[] args)
    {
        Persons psn = new Persons();
        psn.Add("太郎");
        psn.Add("一郎");
        psn.Add("権太");
        for (int i = 0; i < psn.Count; i++)
        {
            Console.Write("{0} ", psn.Names[i]);
        }
    }
}

internal class Persons
{
    public List<string> Names; //インデクサの要素を保持するリスト

    //インデクサ
    public string this[int index]
    {
        get => Names[index];
        set => Names[index] = value;
    }

    //コンストラクタ
    public Persons() => Names = new List<string>();

    //Namesへの追加メソッド
    public void Add(string name) => Names.Add(name);

    //Namesの要素数取得メソッド
    public int Count => Names.Count;
}

出力結果

太郎 一郎 権太

上記コードでは、24~28行目でインデクサが定義されています。上記の24~28行目のコードは、下記と同じです。

    public string this[int index]
    {
        get { return Names[index]; }
        set { Names[index] = value; }
    }

終わりに

式形式のメンバーについて解説しましたが、いかがでしょうか。このような表現は最初に見ると戸惑います。ラムダ式と似ているようで少し違うし。しかし、このような表現を覚えると簡潔に表現できるし、慣れると見た目にもわかりやすいです。

ABOUT ME
しかすけ
日々是好日。何とか何とか生きてます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です