きゅぶろぐ

きゅぶんずの ぶろぐができて べんりだな

Unity2020.2でnull許容参照型を使う

null許容参照型って?

ドキュメントを読みましょう。
これが欲しかった!最高!

Unityで使うには辛さがある

SerializeFieldは#nullable enableで囲う。とかは良いとして、

public class Hoge : MonoBehaviour
{
    private HogeComponent _cache;

    public void Start()
    {
        _cache = GetComponent<HogeComponent>();
    }
}

こういうコードも、コンストラクタで初期化してないのでエラー(正しくは警告ですが)になっちゃうんですよね。
確かにStart呼ばれるまではnullにアクセスする可能性はあるから言ってることは何も間違ってない・・・

戦略

とりあえず、MonoBehaviourに依存していない箇所だけでも有効にしよう。
ということで、↓のコードを突っ込むと、asmdefでNoEngineReferenceがtrueなプロジェクトだけ自動的に有効になります。

Code

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEditor.Experimental;
using UnityEditorInternal;
using UnityEngine;

public class EnableNullable : AssetPostprocessor
{
    private static string OnGeneratedCSProject(string path, string content)
    {
        var assemblyName = Path.GetFileNameWithoutExtension(path);
        var assemblyDefinitionFilePath = CompilationPipeline.GetAssemblyDefinitionFilePathFromAssemblyName(assemblyName);
        if (string.IsNullOrWhiteSpace(assemblyDefinitionFilePath)) return content;

        var assemblyDefinition = EditorResources.Load<AssemblyDefinitionAsset>(assemblyDefinitionFilePath);
        if (!assemblyDefinition.text.Contains("\"noEngineReferences\": true")) return content;

        var document = XDocument.Parse(content);
        if (document.Root == null) throw new Exception($"document.Root == null");

        XNamespace xNamespace = "http://schemas.microsoft.com/developer/msbuild/2003";

        // ReSharper disable once PossibleNullReferenceException
        var propertyGroup = document
            .Element(xNamespace + "Project")
            .Elements(xNamespace + "PropertyGroup")
            .First();
        propertyGroup.Add(new XElement(xNamespace + "Nullable", "enable"));
        return document.ToString();
    }
}

CI

JetBrains CommandLineToolsを2020.3以降にすると、
ちゃんとInspectCodeに引っかかってくれるようになります。