C# 7.0の新機能まとめ

C# 7.0で追加された新機能

  • out変数
  • タプル
  • 破棄
  • パターン一致
  • ref ローカル変数と戻り値
  • ローカル関数
  • 式形式のメンバー追加
  • throw 式
  • 一般化された async の戻り値の型
  • 数値リテラルの構文の改善

out 変数

c# 7.0以前

int num = 0; // 事前に宣言が必要
string s = "100";
bool result = int.TryParse(s, out num);

c# 7.0

string s = "100";
bool result = int.TryParse(s, out int num); // 事前宣言が不要でここで型を指定。varでも可

メリット

  • 事前の宣言が不要になり、コードの可読性が上がる。

タプル

タプルは C# 7.0 より前で使用できましたが、効率的でなく言語サポートがありませんでした。 プロパティ名がItem1、Item2となって値の意味が識別しづらかったです。

c# 7.0

using System;

class Sample
{
  // 返り値を2つ設定
  private (int count, int sum) Tally(int[] items)
  {
    int count = 0;
    int sum = o;
    foreach (item in items)
    {
      sum += item;
      count++;
    }

    return (count, sum);
  }

  static void Main()
  {
    var items = new[] {1, 2, 3, 4, 5};
    var t = Tally(items);
    Console.WriteLine($"count:{t.count} sum:{t.sum}")
  }
}

こちらの記法も可能

var items = new[] {1, 2, 3, 4, 5};
var (count, sum) = Tally(items);
Console.WriteLine($"count:{count} sum:{sum}")

メリット

  • 複数の戻り値を設定可能
  • プロパティに名前の設定が可能

破棄

_ で破棄する値をこの1つの変数に割り当てが可能になります。
タプルの項目で書いたタプルのTally関数に関して、sumだけ必要な場合に以下のように表記できます。

var items = new[] {1, 2, 3, 4, 5};
var (_, sum) = Tally(items);
Console.WriteLine($"sum:{sum}")

パターン一致

is 式と switch 式がパターン一致でサポートされています。

if (input is int count)
{
  Console.WriteLine($"count:"{count});
}
switch (obj)
  {
      case 5:
          Console.WriteLine("5のみ");
          break;
      case int n when n > 0: // 5は上で判定されているため、5以外の正の数
          Console.WriteLine($"正の数:{n}");
          break;
      case int n: // 0以上は上で判定されているため、0以下の整数
          Console.WriteLine(n);
          break;
  }

ref ローカル変数と戻り値

他の場所に定義されている変数への参照を使用したり返したりするアルゴリズムが実現可能になります。 return, メソッド前, 引数前にrefの記入が必要となります。

using System;

class Sample
{
    static void Main()
    {
        var x = 10;
        var y = 20;

        // x, y のうち大きい方の参照を返す。この場合 y を参照する。
        ref var m = ref Max(ref x, ref y);

        // 参照の書き換えのため、その先の y が書き換わる。
        m = 0;

        Console.WriteLine($"{x}, {y}"); // 10, 0
    }

    static ref int Max(ref int x, ref int y)
    {
        if (x < y)
     {
          return ref y;
     }
        else
        {
          return ref x;
       }
    }
}

ローカル関数

関数の中に入れ子で関数を書ける機能のことです。
入れ子の関数は定義した関数の中でだけ使用可能です。

using System;

class Sample
{
    static void Main()
    {
        // 関数の中でローカル関数 calc を定義
        int calc(int a, int b) => a * b / 2;

        Console.WriteLine(calc(4, 6)); // 12
    }
}

式形式のメンバー追加

C# 7.0 では、"コンストラクター"、"ファイナライザー"、get/setアクセサーを "プロパティ" と "インデクサー" に実装できます。

class Sample
{
    private int num;

    // set/getプロパティ
    public int Num
    {
      get => num;
      set => value > 0 ? value : 0;
    }

    // コンストラクター
    Sample() => num++;

    // デストラクター
    ~Sample() => num--;
}

throw 式

throw 式を使用して、メソッドに空の文字列配列が渡された場合に ArgumentException をスローします。
対象の場所は、「条件演算子」、「null 合体演算子」、「式形式のラムダまたはメソッド」です。
C# 7.0 以前では、このロジックが if/else ステートメントで使用されている必要がありました。

// 式形式メンバーの中( => の直後)
static void Sample1() => throw new NotImplementedException();

static string Sample2(object obj)
{
    // null 合体演算子(??)の後ろ
    var s = obj as string ?? throw new ArgumentException(nameof(obj));

    // 条件演算子(?:)の条件以外の部分
    return s.Length > 0 ? "OK" : throw new InvalidOperationException("string is Empty");
}

一般化された async の戻り値の型

非同期メソッドの戻り値の型が Task、Task、void に限定されなくなりました。

数値リテラルの構文の改善

2進数リテラルの表記が可能になりました。先頭に0bを付けると2進数リテラルになります。
バイナリ数値は非常に長くなる場合があるため、桁区切り記号として _が導入されました。

public const int Sixteen =   0b0001_0000; // 16

public const long OneHundredMillion = 100_000_000; // 1億

参考

C# 7.0 の新機能 - C# ガイド | Microsoft Docs

C# 7 の新機能 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C