第2回 簡潔なコーディングのために特集:C# 7の新機能詳説(1/2 ページ)

ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている。

» 2017年07月26日 05時00分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Development]
「特集:C# 7の新機能詳説」のインデックス

連載目次

 Visual Studio 2017とともにリリースされたC# 7には多くの新機能がある。それらの新機能はどのような場面で役立つのだろうか? 3回にわたって紹介していく。

簡潔なコーディングのために

 コードを短く要領よく書きたいとは、プログラマーなら誰しもが思うことだろう。今回は、簡潔なコーディングに役立つC# 7の新機能を紹介する。

  • 本体が式のメンバの拡大
  • throw式
  • out変数
  • タブルの生成と分解

本体が式のメンバの拡大

 クラスメンバの本体をラムダ式の形で簡潔に記述できる機能である。

 C# 6では、次に示すメンバが対応していた。

  • 通常のメソッド
  • 演算子
  • 読み取り専用のプロパティ/インデクサー

 C# 7では、以下のメンバにも拡張された。およそあらゆるメンバがラムダ式で記述可能になったといえるだろう。

  • コンストラクタ/デストラクタ
  • プロパティ/インデクサーのget/set
  • イベントのadd/remove

プロパティをラムダ式で記述する

 プロパティやインデクサーをラムダ式で記述する場合、読み取り専用ならば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}";
  //}
}

プロパティをラムダ式で記述する例(C# 7)
C# 7では、プロパティのget/setを別々にラムダ式で記述できるようになった。
読み取り専用プロパティの場合は、C# 6の形式(getキーワードを書かない)で書いた方が簡潔になる。
なお、このサンプルコードはINotifyPropertyChangedインタフェース(System.ComponentModel名前空間)の実装例になっている。読み書き可能なDateプロパティはデータバインディングに対応している。INotifyPropertyChangedインタフェース登場時にその実装をした経験のある開発者は、このDateプロパティの簡潔さに驚くかもしれない。また、INotifyPropertyChangedインタフェースのヘルパーメソッドの1つ、OnPropertyChangedメソッドもラムダ式で実装している。

throw式

 これは、throwステートメントを特別な場所でだけ式として扱うものだ。何だか難しそうだが、以下に示す3箇所にもthrowが書けるようになったのだ。

  • 式形式のラムダ式の中(「=>」の後ろ)
  • null合体演算子「??」の後ろ
  • 条件演算子(三項演算子)「?:」の後ろ

式形式のラムダ式の中で例外を投げる

 今までは式形式のラムダ式の中で例外を投げられなかった。そのため、取りあえずコンパイルを通すためだけにメンバを書いておいて後からちゃんと実装するような場合には、次のコードに示すような手順を踏んでいた。

public string SampleMethod()
{
  // コンパイルを通すためだけの仮実装
  // 後で実装するのを忘れないよう、例外を投げるようにしておく
  throw new NotImplementedException();
}
// ↓ 後からちゃんと実装する
public string SampleMethod()
{
  return "Hello, world!";
}
// ↓ ラムダ式にして簡潔に
public string SampleMethod() => "Hello, world!";

本体がラムダ式のメソッドを実装する手順の例(C# 6まで)
最初に、コンパイルを通すためだけの仮実装を行う。このとき、後で実装するのを忘れないように、メソッド本体はNotImplementedException例外を投げるようにしておきたいとする。すると、C# 6までは式形式のラムダ式の中にthrowステートメントは書けなかったので、通常の形式でメソッドを書かねばならない。
次に、メソッドの中身をちゃんと実装し、それからラムダ式に書き直して簡潔にする。この2ステップは同時にやってもよいが、いずれにせよ、最初に普通の形式でメソッドを書かねばならないのは面倒だ。

 C# 7では、最初からラムダ式で書ける(次のコード)。

// C# 7では、最初からラムダ式で書ける
public string SampleMethod() => throw new NotImplementedException();
// ↓ 後からちゃんと実装する
public string SampleMethod() => "Hello, world!";

本体がラムダ式のメソッドを実装する手順の例(C# 7)
C# 7では、式形式のラムダ式にthrowを置けるので、仮実装のときからラムダ式で書き始められる。

null合体演算子や条件演算子の中で例外を投げる

 例として、引数が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());
}

nullのときに独自の例外を投げる例(C# 6まで)

 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式を使って簡潔に独自の例外を投げる例(C# 7)

 あるいは、キャストする必要がなくてただnull判定をする場合は、次のコードのように条件演算子(三項演算子)の中でthrowできる。

public static string Reverse2(string s)
  => string.IsNullOrWhiteSpace(s)
    ? throw new ApplicationException()
    : new string(s.Reverse().ToArray());

nullのときにthrow式を使って簡潔に独自の例外を投げる例(C# 7)

       1|2 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。