コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】Unity 2020.2a から C# 8.0 の機能がいくつか使用できるようになった

はじめに

Unity 2020.2a から C# 8.0 の機能がいくつか使用できるようになりました

マイクロソフトの公式ページで C# 8.0 の新機能が紹介されておりますが、
この新機能の中から、現時点で使用できることが確認できた機能と
使用できなかった機能をいくつか紹介していきます

検証環境

  • Unity 2020.2.0a21
  • Visual Studio 2019

目次

使えた機能

読み取り専用メンバー

using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        var character = new Character();
        Debug.Log(character.Name);
        Debug.Log(character.GetName());
    }
}

public struct Character
{
    // ★
    public readonly string Name => "ピカチュウ";

    // ★
    public readonly string GetName() => "ピカチュウ";
}

switch 式

using System;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log(GetName(3)); // フシギバナ
    }

    private string GetName(int i)
    {
        // ★
        return i switch
        {
            1 => "フシギダネ",
            2 => "フシギソウ",
            3 => "フシギバナ",
            _ => throw new ArgumentException(),
        };
    }
}

プロパティパターン

using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log(GetName(Vector2Int.up)); // 上
    }

    private string GetName(Vector2Int vec)
    {
        // ★
        return vec switch
        {
            { x: -1, y:  0 } => "左",
            { x:  1, y:  0 } => "右",
            { x:  0, y:  1 } => "上",
            { x:  0, y: -1 } => "下",
        };
    }
}

タプルパターン

using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log(GetName(0, 1)); // 上
    }

    private string GetName(int x, int y)
    {
        // ★
        return (x, y) switch
        {
            { x: -1, y:  0 } => "左",
            { x:  1, y:  0 } => "右",
            { x:  0, y:  1 } => "上",
            { x:  0, y: -1 } => "下",
        };
    }
}

位置指定パターン

using UnityEngine;

public static class Vector2IntExt
{
    public static void Deconstruct
    (
        this Vector2Int self,
        out float x,
        out float y
    )
    {
        x = self.x;
        y = self.y;
    }
}

public class Example : MonoBehaviour
{
    private void Awake()
    {
        Debug.Log(GetName(Vector2Int.up)); // 上
    }

    private string GetName(Vector2Int vec)
    {
        // ★
        return vec switch
        {
            var (x, y) when x < 0 && y == 0 => "左",
            var (x, y) when 0 < x && y == 0 => "右",
            var (x, y) when x == 0 && 0 < y => "上",
            var (x, y) when x == 0 && y < 0 => "下",
        };
    }
}

using 宣言

using System;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        // ★
        using var character = new Character();

        Debug.Log("ピカチュウ");

        // Awake 関数を抜ける時に「カイリュー」と出力される
    }
}

public class Character : IDisposable
{
    public void Dispose()
    {
        Debug.Log("カイリュー");
    }
}

静的ローカル関数

using System;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        // ★
        static string GetName() => "ピカチュウ";

        Debug.Log(GetName());
    }
}

null 許容参照型

using UnityEngine;

// ★
#nullable enable

public class Example : MonoBehaviour
{
    // ★
    string? GetName() => null;

    private void Awake()
    {
        Debug.Log(GetName());
    }
}

null 合体割り当て

using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        string name = null;

        // ★
        Debug.Log( name ??= "ピカチュウ" ); // ピカチュウ
        Debug.Log( name ??= "カイリュー" ); // ピカチュウ
    }
}

verbatim 補間文字列の拡張

using UnityEngine;

public class Example : MonoBehaviour
{
    private void Awake()
    {
        var dir = "tmp";
        Debug.Log( $@"C:\{dir}" ); // C# 7.3 以前も使用可
        Debug.Log( @$"C:\{dir}" ); // C# 8 以降から使用可
    }
}

使えなかった機能

既定のインターフェイスメソッド

error CS8701: Target runtime doesn't support default interface implementation.
  • 既定のインターフェイスメソッド定義したところ
    上記のコンパイルエラーが発生して使用できなかった

非同期ストリーム

  • .NET Standard 2.1 がサポートされていない関係で
    System.Collections.Generic.IAsyncEnumerable が見つからず使用できなかった

インデックスと範囲

  • .NET Standard 2.1 がサポートされていない関係で
    System.Index と System.Range が見つからず使用できなかった

補足

Visual Studio 2019 が必要

Visual Studio 2017 は基本的には C# 8.0 に対応していないため
Unity 2020.2a + Visual Studio で C# 8.0 を使用したい場合は
Visual Studio 2019 をインストールする必要があります

一応、下記のページを見る限り Visual Studio 2017 で
C# 8.0 を使用する方法もあるようですが未検証

https://stackoverflow.com/questions/54701377/how-can-i-use-c-sharp-8-with-visual-studio-2017

.csproj の言語バージョンに 8.0 を指定するエディタ拡張が必要

少なくとも Unity 2020.2.0a21 で .csproj を生成すると
生成された .csproj の言語バージョンが 7.3 になっているため、
C# 8.0 の機能を使用してコーディングすると
Visual Studio 側でエラーが表示されてしまいます

上記ページで公開されているエディタ拡張を Unity プロジェクトに追加すると
生成される .csproj の言語バージョンが 8.0 に置き換わるため、
Visual Studio 上で C# 8.0 の機能を使用してもエラーが表示されないようになります

エディタ拡張のスクリプト(引用)

参考サイト様