Logo wizaman's blog (legacy)

Unity 5.5-5.6でC# 6を使う

September 3, 2017
8 min read
Table of Contents

Unity 5.5からC#コンパイラがアップデートされたので、C# 6としてのコンパイルが可能です。

但し、標準ライブラリ側が.NET Framework 3.5相当のまま古いので、C# 6の言語機能をすべて使えるわけではありません。async/awaitなど新しいライブラリに依存する機能は使えず、シンタックスシュガーである文字列補間などは問題なく使えます。

そういった事情からか、Unity 5.5~5.6ではデフォルトでC# 4としてビルドされるようになっています。これをC# 6でビルドさせるように修正する方法をまとめます。

C# 6でコンパイルする

Assets直下にmcs.rspというテキストファイルを配置して、-langversion:6という1行を書き加えればC# 6でコンパイルされるようになります。

但し、.rspファイルを変更しても再コンパイルされないので、スクリプト側で何らかの修正を入れて再コンパイルを走らせるか、Unityエディタを起動し直すかしないと反映されません。

mcs.rspはUnity 5.4まではsmcs.rspgmcs.rspとして配置するものでしたが、Unity 5.5でまとめられた形になります。-define:HOGEのように書いてdefineシンボルを定義したりできます。その用途ではPlayer SettingsのScripting Define Symbolsを使うのが良いと思いますが。

プロジェクトファイルを修正する

先程の.rspファイルによる設定で、C# 6としてコンパイルされるようになりました。

が、Visual Studioでプロジェクトを開くとC# 4として認識しているため、C# 6の機能を使うとVisual Studio側でエラーだと判断します。とてもコーディングしづらい。

Unity側は問題ないので、これはUnityが書き出したVisual Studioのプロジェクトファイル(.csproj)がまずいです。

中身を見ると下記の行が悪さをしていることがわかります。

<LangVersion Condition=" '$(VisualStudioVersion)' != '10.0' ">4</LangVersion>

この行を削除するか、バージョンを4から6指定に変更することで、Visual StudioにもC# 6として認識させることができます。

とはいえ、勝手に生成されるプロジェクトファイルを都度、手で修正するのは手間がかかりすぎます。

そんなときのためにVisual Studio Tools for Unity(VSTU)のProjectFileGenerationが使えます。VSTUはUnityとVisual Studioが連携するための機能で、かつてUnityVSと呼ばれていたものですね。最近はUnityインストーラで一緒に入れてくれるのでありがたい。

上記の通り、プロジェクトファイル生成処理をフックして、プロジェクトファイルを修正するエディタスクリプトのサンプルがMicrosoftのドキュメントに掲載されています。ファイル名と内容を受け取って、修正後の内容をreturnする、という処理をコールバックに登録するだけのようです。プロジェクトファイルはXMLで書かれているため、サンプルではLINQ to XMLを使って編集しています。

これを参考に、C#のバージョン指定を6にしてみます。

#if ENABLE_VSTU
using System.IO;
using System.Text;
using System.Xml.Linq;
using UnityEngine;
using UnityEditor;
using SyntaxTree.VisualStudio.Unity.Bridge;
 
[InitializeOnLoad]
public static class VSProjectHook
{
    private static readonly XNamespace xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";
 
    private class Utf8StringWriter : StringWriter
    {
        public override Encoding Encoding
        {
            get { return Encoding.UTF8; }
        }
    }
 
    static VSProjectHook()
    {
        ProjectFilesGenerator.ProjectFileGeneration += onGenerateProject;
    }
 
    private static string onGenerateProject(string name, string content)
    {
        Debug.Log("Generate VS Project: " + name);
 
        var doc = XDocument.Parse(content);
 
#if !UNITY_2017
        // C#バージョン修正
        modifyCsharpVersion(doc, "6");
#endif
 
        var writer = new Utf8StringWriter();
        doc.Save(writer);
        return writer.ToString();
    }
 
    private static void modifyCsharpVersion(XDocument doc, string version)
    {
        var project = doc.Element(xmlns + "Project");
        if(project == null) {
            Debug.LogWarning("<Project> is not found.");
            return;
        }
 
        foreach(var group in project.Elements(xmlns + "PropertyGroup")) {
            foreach(var langVersion in group.Elements(xmlns + "LangVersion")) {
                langVersion.Value = version;
            }
        }
    }
}
#endif

プロジェクトファイルに追加されるアセット集合に変更がなければこの修正は反映されない(?)ようなので、一度、ソリューションファイル(.sln)とプロジェクトファイル(.csproj)をすべて削除しておくといいです。その状態でUnityからスクリプトを開こうとすると、自動でプロジェクトファイルが生成されます。

若干階層深いのでXPath指定してXPathSelectElementsで要素を取ってきたかったのですが、どうもデフォルト名前空間との相性が悪いみたいですっきり解決する方法がわかりませんでした。このへん知識も経験も足りなくてわからん。XPathはパフォーマンス的にもイマイチらしいので大人しくLINQ to XMLで統一しました。

VSTUが有効な環境でのみ、このスクリプトは使えるので、#if ENABLE_VSTUとしてVSTUが有効な環境でのみコンパイルされるようにしています。

公式なドキュメントでENABLE_VSTUシンボルについて説明されているのを見たことがないですが、こういうシンボルは色々あります。プロジェクトファイルの中に、DefineConstants要素として定義済みシンボルがまとめられているので、一度目を通しておくといいと思います。Unityサービス系も色々と定義されています。

Unity 2017以降

Unity 2017では実験的(Experimental)機能としてですが、標準ライブラリを.NET Framework 4.6相当に変更できる設定が追加されたことで、C# 6の機能が使えるようになっています。詳細は下記の記事を参照。

なので、今回書いたことはあくまでUnity 5.5~5.6の話です。Unity 2017にさっさと移行するのが良いと思いますが、プロジェクトファイルの修正方法をまとめたかったのが今回の本当の目的です。