ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている。
Visual Studio 2017とともにリリースされたC# 7には多くの新機能がある。それらの新機能はどのような場面で役立つのだろうか? 3回にわたって紹介していく。
コードを短く要領よく書きたいとは、プログラマーなら誰しもが思うことだろう。今回は、簡潔なコーディングに役立つC# 7の新機能を紹介する。
クラスメンバの本体をラムダ式の形で簡潔に記述できる機能である。
C# 6では、次に示すメンバが対応していた。
C# 7では、以下のメンバにも拡張された。およそあらゆるメンバがラムダ式で記述可能になったといえるだろう。
プロパティやインデクサーをラムダ式で記述する場合、読み取り専用ならばC# 6の形式を、読み書き可能なときはget/setを個別にラムダ式で書くC# 7の形式を使うとよい。
プロパティをラムダ式で記述する例を次のコードに示す。
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public abstract class BindableBase : INotifyPropertyChanged
{
// INotifyPropertyChangedインタフェースの実装と、ヘルパーメソッド
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected void SetProperty<T>(ref T storage, T value,
[CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value))
return;
storage = value;
OnPropertyChanged(propertyName);
}
}
public class ABindableClass : BindableBase
{
// 読み書きするプロパティは、get/setそれぞれをラムダ式で記述できる
private DateTimeOffset _date;
public DateTimeOffset Date
{
get => _date;
set => SetProperty(ref _date, value);
}
// 読み取り専用プロパティは、次のような形でラムダ式を使える
public string NowTime => $"{DateTimeOffset.Now:HH:mm:ss}";
// これはC# 7では次のように書くこともできるが、かえって長くなる
//public string NowTime
//{
// get => $"{DateTimeOffset.Now:HH:mm:ss}";
//}
}
これは、throwステートメントを特別な場所でだけ式として扱うものだ。何だか難しそうだが、以下に示す3箇所にもthrowが書けるようになったのだ。
今までは式形式のラムダ式の中で例外を投げられなかった。そのため、取りあえずコンパイルを通すためだけにメンバを書いておいて後からちゃんと実装するような場合には、次のコードに示すような手順を踏んでいた。
public string SampleMethod()
{
// コンパイルを通すためだけの仮実装
// 後で実装するのを忘れないよう、例外を投げるようにしておく
throw new NotImplementedException();
}
// ↓ 後からちゃんと実装する
public string SampleMethod()
{
return "Hello, world!";
}
// ↓ ラムダ式にして簡潔に
public string SampleMethod() => "Hello, world!";
C# 7では、最初からラムダ式で書ける(次のコード)。
// C# 7では、最初からラムダ式で書ける
public string SampleMethod() => throw new NotImplementedException();
// ↓ 後からちゃんと実装する
public string SampleMethod() => "Hello, world!";
例として、引数がnullだったときに、ArgumentNullException例外(System名前空間)に代えて独自の例外(例えばSystem名前空間のApplicationException例外)を出したいとしよう。
これまでであれば、次のコードのようにnull判定を行ってthrowステートメントを書いていた。
public static string Reverse(object o)
{
// nullのとき、ArgumentNullException例外ではなく、独自の例外を出したい
var s = o as string;
if (s == null)
throw new ApplicationException();
return new string(s.Reverse().ToArray());
}
C# 7では、上のコードはnull合体演算子を使って簡潔に書ける(次のコード)。
public static string Reverse(object o)
{
var s = o as string ?? throw new ApplicationException();
return new string(s.Reverse().ToArray());
}
あるいは、キャストする必要がなくてただnull判定をする場合は、次のコードのように条件演算子(三項演算子)の中でthrowできる。
public static string Reverse2(string s)
=> string.IsNullOrWhiteSpace(s)
? throw new ApplicationException()
: new string(s.Reverse().ToArray());
Copyright© Digital Advantage Corp. All Rights Reserved.