[C# 7] Visual Studio 2017 RC でC# 7の新機能を試してみた

vscode

はじめに

こんにちは!モバイルアプリサービス部の加藤潤です。
先日発表されたVisual Studio for Macが注目を集めていますが、同時に時期バージョンのVisual Studio、「Visual Studio 2017」のRC版もリリースされました。 このバージョンではC# 7の機能を試すことができるので勉強も兼ねて試してみました!

開発環境

  • Windows 10 Pro
  • Visual Studio Community 2017 RC

インストール

Visual Studio(以下、VS)2017 RCのインストーラーはこちらからダウンロードすることができます。

インストールもカテゴリ分けされていてだいぶわかり易くなりましたね。今回は「.NETデスクトップ開発」を選んでみました。 001

C# 7の新機能

タプル

こちらはVSをインストールしただけでは使えないようです。以下のように別途NuGetでSystem.ValueTupleパッケージをインストールする必要があります。 002

パッケージをインストールすると、以下のようにタプルが使えるようになります。

// 明示的な型指定(メンバー名指定なし)
(int, string) result = (200, "OK");

// メンバーにはItemNでアクセス可能
WriteLine($"{result.Item1},{result.Item2}"); // 200,OK

// 明示的な型指定(メンバー名指定あり)
(int code, string message) result = (200, "OK");

// メンバー名でアクセス可能
WriteLine($"{result.code},{result.message}"); // 200,OK

型推論も効きます。

// 型推論
var result = (code: 200, message: "OK");

引数や戻り値にも使えます。

static (int code, string message) GetResult((int, int)param)
{
    return (400, "Bad Request");
}

// 引数や戻り値にも使える
var result = GetResult((1, 2));
WriteLine($"{result.code},{result.message}"); // 400,Bad Request

タプルを分解して別の変数に格納することも可能です。

// タプルの分解
var (v1, v2) = result;

ローカル関数

関数の中に関数を定義することが出来るようになりました。 下の例ではMain関数内でのみ使えるローカル関数addを定義しています。

static void Main(string[] args)
{
    // ローカル関数
    int add(int x, int y) => x + y;

    WriteLine(add(3, 5)); // 8
}

型スイッチ

is演算子を使って型を判定すると同時にその型の変数が使えるようになりました。

object obj = "test";
if (obj is string s)
{
    WriteLine(s); // test
}

これによって、特にnull許容型で値を取得する際にスッキリ書けるようです。

int? intOrNull = 100;

// C# 7以前
if (intOrNull.HasValue)
{
    var value = intOrNull.GetValueOrDefault();
    WriteLine($"value is {value}");
}

// C# 7
if (intOrNull is int v)
{
    WriteLine($"value is {v}");
}

また、switchステートメントのcaseでも型による分岐ができるようになりました。
さらにwhenを使った条件(case guard)も記述できます。

object obj = 99;
switch (obj)
{
    case "test":
        WriteLine();
        break;
    case int v when 100 < v:
        WriteLine($"{v} is greater than 100");
        break;
    case int v:
        WriteLine(v); // ここを通る
        break;
    default:
        WriteLine("default");
        break;
}

出力変数宣言

以下のようなstructの定義があったとして、GetCoordinatesメソッドの出力変数でxとyの値を取得したい場合を考えます。

struct Point
{
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    public int X { get; }
    public int Y { get; }

    public void GetCoordinates(out int x, out int y)
    {
        x = X;
        y = Y;
    }
}

以前はout引数を受け取る前に変数宣言が必要でしたが、C# 7では引数受け取りと同時に変数の宣言ができるようになりました。

// C# 7以前
var p = new Point(100, 200);
// 事前に変数の宣言が必要
int x, y;
p.GetCoordinates(out x, out y);
WriteLine($"({x},{y})"); // (100,200)

// C# 7
var p = new Point(100, 200);
p.GetCoordinates(out int x, out int y);
WriteLine($"({x},{y})"); // (100,200)

型推論も使えます。

p.GetCoordinates(out var x, out var y);

その他

おわりに

C#も着実により便利に進化していますね。ScalaやF#に影響を受けているパターンマッチはまだまだ一部の実装にとどまっていますが、C# 8以降で更なる進化を遂げることと思います。
Xamarinも現状はC# 6での開発ですが、いずれC# 7が使えるようになることでしょう。
Scalaや関数型言語などの他の言語の良いところをうまく取り込んでいく姿勢が見えます。そういう意味ではだんだんと言語の垣根は無くなってきていると感じます。

参考