Unity 2020.2 から使える C# 8.0 の機能紹介!

Unity 2020.2 から使える C# 8.0 の機能紹介

はじめに

Unity 2020.2 で C# 8.0 の機能がサポートされました。
本記事ではUnity 2020.2 から使える C# 8.0 の機能を紹介します。

C# 8.0
参考 C#8.0の新機能Microsoft Docs

C# 8.0 の機能

読み取り専用メンバー

構造体のメンバーに readonly 修飾子が適用可能になり、書き換え不可を保証できるようになりました。

public struct Address
{
    public float X { get; set; }
    public float Y { get; set; }

    // メンバーに readonly 修飾子を適用可能に
    public readonly override string ToString() => $"X: {X}, Y: {Y}";
}

switch 式

switch を式として記述でき、より簡潔で伝わりやすい構文が書けるようになりました。

public enum Fruit
{
    Apple,
    Banana,
    Melon,
}

public static Color ToColor(Fruit fruit) =>
    fruit switch
    {
        Fruit.Apple  => Color.red,
        Fruit.Banana => Color.yellow,
        Fruit.Melon  => Color.green,
        _            => throw new ArgumentException(message: "invalid enum value", paramName: nameof(fruit)),
    };
}

switch 構文の改良点

  • 変数を switch キーワードの前に記述
  • case:=>に置き換え可能
  • default_に書き換え可能

プロパティ パターン

switch 文からプロパティにアクセスして式を記述できるようになりました。プロパティ名と:の後に条件にマッチさせたい値を記載します。複数のプロパティを扱う場合は ,で区切ります。

以下は先程記載した Addressクラスを参考に、プロパティのXYを使ったパターン例です。

static int MatchNum(Address address) =>
    address switch
    {
        {X: 1, Y: 1} => 1,
        {X: 2, Y: 2} => 2,
        {X: _, Y: 3} => 3,
        _            => -1,
    };
}

タプル パターン

Switch 式でタプルが使用可能になりました。

public static string AttributeResult(string first, string second)
    => (first, second) switch
    {
        ("Fire", "Water") => "Water wins.",
        ("Fire", "Grass") => "Fire wins.",
        ("Water", "Fire") => "Water wins.",
        ("Water", "Grass") => "Grass wins.",
        ("Grass", "Fire") => "Fire wins.",
        ("Grass", "Water") => "Grass wins.",
        (_, _) => "Invalid"
    };
}

using 宣言

変数宣言時に using を付けられるようになりました。これは using ステートメントと同じ処理が行われます。

static void Main()
{
    // 変数宣言前の using で、スコープを抜ける時に Dispose が呼ばれる
    using var fs = new FileStream("sample.txt", FileMode.Open);
    Console.WriteLine(fs.Length);
    // ここで Dispose が呼ばれる
}

C# 7.3 以前の using ステートメントの書き方

static void Main()
{
    using (var fs = new FileStream("sample.txt", FileMode.Open))
    {
        Console.WriteLine(fs.Length);
    }
}

静的ローカル関数

ローカル関数に static修飾子を付けられるようになりました。これを静的ローカル関数と呼び、ローカル関数で外部変数が参照されない設定が可能になります。

void Test(int num)
{
    // 外部の変数である num を使用可能
    int Add(int x) => num + x;

    // static を付けると外部変数の num が参照不可になる
    // この場合コンパイルエラーが発生
    static int Minus(int x) => num - x;
}

null 許容参照型

参照型の変数はすべて「null 非許容参照型」と見なされますが、変数宣言時に型名に?と書くことで null が許容であることを示す「null 許容参照型」として扱えるようになりました。

これはディレクティブに#nullable enableを記載することで有効になります。

// null 許容参照型 を有効にする
#nullable enable

class Program
{
    string str1 = string.Empty;
    string str2 = null;
    string? str3 = null;

    void TextLength()
    {
        // str2 は null の可能性があるが警告エラーなし
        int textLength1 = str1.Length + str2.Length;

        // str3 に null の可能性を示す警告エラーが出る
        int textLength2 = str1.Length + str3.Length; // warning CS8602: Dereference of a possibly null reference.
    }
}

参照型を null 許容参照型 として宣言することで、コンパイラにてフロー解析が行われます。これにより意図しない null エラーを事前に避けることができます。

null 合体割り当て

null 合体割り当て演算子 ??= が使えるようになりました。

左側のオペランドが null の場合に??=を使用して右側のオペランドの値を左側に割り当てられます。

static void Test(string str = null)
{
    str ??= "sample text";
    Console.WriteLine(str);
}

verbatim 補間文字列の拡張

C# 7.3 以前では、文字列リテラルの前に$@と付けることで複数行の文字列補間が可能でした。C# 8.0 から @$、つまり表記が逆でも文字列補間が認められるようになりました。

// C# 7.3 以前から使用可
var sample1 = $@"
    sample
    test";

// C# 8.0 から使用可
var sample2 = @$"
    sample
    test";
}

参考資料

参考 C#8.0の新機能Microsoft Docs 参考 C# 8.0 の新機能++C++; // 未確認飛行 C 参考 【Unity】Unity 2020.2a から C# 8.0 の機能がいくつか使用できるようになったコガネブログ
C#に関するパフォーマンス最適化のTips 【Unity】C#に関するパフォーマンス最適化のTips