コンテンツにスキップ

境界の一覧

書き方説明
class MyError : System.Exception { }例外の型の宣言
public delegate int Op(int a);デリゲートの宣言
private Op F;デリゲート型のフィールド
/// <summary>…</summary>説明のコメント
#nullable enable / string? snull になりうる注釈
[NotNull]null 解析の属性
[NotNullWhen(true)] out string s戻り値が真なら null でない指定
[return: MaybeNull]null を返しうる指定
[AllowNull]null を入れてよい指定
#nullable disable検査の無効化
書き方説明エラー理由代わりに
throw;捕まえた例外を投げ直すTUKI0001環境戻り値や状態で失敗を表す
catch { … }型を書かずに捕まえるTUKI0001環境同上
yield return / yield break値を 1 つずつ返すTUKI0001, TUKI0099環境配列に詰めて返す
IEnumerator<int> Nums()イテレータを返すTUKI0001, TUKI0099環境同上
async Task Run()非同期のメソッドを書くTUKI0001, TUKI0101環境イベントで分けて書く
async void Run()戻り値の無い非同期メソッドTUKI0001, TUKI0101環境同上
await …完了を待つTUKI0001環境同上
System.Func<int,int> f = x => x + 1;ラムダ式を変数に入れるTUKI0108, TUKI0001環境メソッドを名前で呼ぶ
() => n外側の変数を捕まえるラムダ式TUKI0108, TUKI0001環境捕まえたい値を引数で渡して、メソッドを名前で呼ぶ
[DllImport("x")]外部のライブラリを呼ぶTUKI0001環境実行環境のメソッドを使う
dynamic d = 1; d.ToString()実行時にメンバを名前で解決するTUKI0102, TUKI0099環境型を書く
宣言だけが通ることは、使えることを意味しません。例外の型もデリゲートも、宣言はコンパイラを通り、使う行を書いた瞬間に初めて断られます

LINQ は、イテレータやデリゲートの有無ではなく、名前空間が無いこととして断られます。using System.Linq; の 1 行だけで CS0234 が出て、コンパイラは System.Linq が見つからないと言います。

素通しになる形は、断られないぶん紛らわしいものです。説明のコメントも null の注釈も書けますが、実行時の意味は変わりません。

例外の型は宣言できますが、投げることも捕まえることもできません。

using UnityEngine;
using Tsukimi;
public class MyError : System.Exception { }
public class ExCustom : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
}

デリゲートの型は宣言できますが、その型の値を作れません。

using UnityEngine;
using Tsukimi;
public delegate int Op(int a);
public class DlDeclared : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
}

フィールドは宣言できますが、入れる値を作れません。

using UnityEngine;
using Tsukimi;
public delegate int Op(int a);
public class DlField : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
private Op F;
}

説明のコメントは書けますが、どこにも出ません。

using UnityEngine;
using Tsukimi;
public class DcComment : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
/// <summary>説明</summary>
private int Helper() { return 1; }
}

? の付いた型は C# の検査に効きますが、実行時のふるまいは変わりません。

using UnityEngine;
using Tsukimi;
public class NrAnnot : TsukimiBehaviour
{
void Start()
{
#nullable enable
string? s = null;
Debug.Log(s == null); // => true
}
}

[NotNull] も C# の解析にだけ効きます。

using UnityEngine;
using Tsukimi;
public class NrAttr : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
[System.Diagnostics.CodeAnalysis.NotNull]
private string S = "a";
}

戻り値が真なら null でない指定

Section titled “戻り値が真なら null でない指定”

[NotNullWhen(true)] は C# の解析に伝わりますが、実行時のふるまいは変わりません。

using UnityEngine;
using Tsukimi;
public class NrNotNullWhen : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
private bool Try([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string s) { s = "a"; return true; }
}

[return: MaybeNull] も C# の解析にだけ効きます。

using UnityEngine;
using Tsukimi;
public class NrMaybeNull : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
[return: System.Diagnostics.CodeAnalysis.MaybeNull]
private string Get() { return null; }
}

[AllowNull] も C# の解析にだけ効きます。

using UnityEngine;
using Tsukimi;
public class NrAllowNull : TsukimiBehaviour
{
void Start()
{
Debug.Log(1); // => 1
}
[System.Diagnostics.CodeAnalysis.AllowNull]
private string S = "a";
}

#nullable disable を書いた行から先で、null 安全の検査が切れます。

#nullable enable
using UnityEngine;
using Tsukimi;
public class NrDisable : TsukimiBehaviour
{
void Start()
{
#nullable disable
string s = null;
Debug.Log(s == null); // => true
}
}

境界は言語の側だけではありません。触れる型の側にもあります。この環境が公開している のは Unity と VRChat の型の一部で、そこに無い型を変数に書くと TUKI0102 で断られます。 型があっても、その中の呼び出しが全部あるとは限りません。公開されていない呼び出しは TUKI0101 で断られます。

どの型に何があるかの一覧は、この文書では持ちません。Unity の型は Unity の スクリプトリファレンスに、VRChat の型は VRChat の制作者向けドキュメントにあります。 この文書が扱うのは、その手前にある言語の側の境界です。