この記事では式形式のメンバーについて解説します。
式形式のメンバーとは
式形式のメンバーは、英語では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; }
}終わりに
式形式のメンバーについて解説しましたが、いかがでしょうか。このような表現は最初に見ると戸惑います。ラムダ式と似ているようで少し違うし。しかし、このような表現を覚えると簡潔に表現できるし、慣れると見た目にもわかりやすいです。

