対応状況

いま何がコンパイルできるのか、そして Udon が決して実行できない C# の部分について。

更新日 2026-09-08

Udonite は日常的な C# のかなり広い範囲をコンパイルします。以下の構文はすべて、出力をアセンブルして実機の Udon 仮想マシンで動かすテストで確認しています。

コンパイルできるもの

型とメンバー

class struct interface enum record(宣言が一つ必要) 入れ子の型 自作クラスをフィールドやローカルに 制約付きジェネリクス インターフェースの既定実装 プロパティとインデクサー 拡張メソッド 省略可能引数と名前付き引数 params outref の引数 タプルと分解 値としての typeof ローカル関数 静的ヘルパークラス

レコード:位置指定のコンストラクタ、with、値等価性、ToString、分解。ただし、自分のスクリプトに次の宣言を一つ置く必要があります。recordinit セッターは init 専用プロパティにコンパイルされますが、Unity がワールドのコードをビルドする .NET のクラスライブラリには System.Runtime.CompilerServices.IsExternalInit がないためです。これがないと、Udonite が動くより前に Unity 自身のコンパイラが CS0518 でビルドを止めます。

namespace System.Runtime.CompilerServices
{
    internal static class IsExternalInit { }
}

record struct と構造体に対する with は C# 10 の機能で、Unity は C# 9 でコンパイルするため、こちらはまったく使えません。static フィールドは constreadonly である必要があります(後述)。

継承

abstract クラス abstract メンバー virtualoverride base. 呼び出し abstract な behaviour

基底型を通した呼び出しは最も派生したオーバーライドに届き、base.Method() はちょうど一段上に届きます。ふつうのクラスでも、GameObject に載った behaviour でも同じです。

コンポーネント同士が契約を共有する手段は abstract な基底クラスです。Unity はインターフェースのフィールドをシリアライズできないからです。インターフェース を参照してください。

文と式

制御フロー switch 式 パターンマッチング null 演算子 文字列補間 算術・ビット・シフト演算子 フラグ enum 配列と多次元配列 範囲とインデックス Array のヘルパー List<T> Dictionary<K,V> HashSet<T> Queue<T> Stack<T> LINQ デリゲートとイベント ラムダ 文字列と StringBuilder null 許容値型 enum の解析と名前 try / finally throw 再帰

制御フローは ifswitchforforeachwhiledobreakcontinue です。パターンマッチングは型パターン、is not nullis > 5 and < 10 のような関係パターン、プロパティパターンと位置パターン、when ガードを含みます。null 演算子は ?.????= です。補間文字列は書式指定子を受け付け、nameof もコンパイルできます。範囲とインデックスは arr[^1]arr[1..3]、そして文字列に対する同じ書き方(text[1..3]text[^2..]text[..^1])です。typeof(T) は値として扱えます。ローカル変数、フィールド、引数、配列に保持でき、==Equals で比較でき、IsAssignableFromIsInstanceOfType も呼べます。typeof(T).Name.FullName はコンパイル時に文字列へ畳み込まれます。Array のヘルパーは SortFindFindAllFindLastExistsIndexOfLastIndexOfResizeCopyFillConvertAll です。

配列・リスト・ディクショナリに対する LINQ:SelectWhereOrderByThenByGroupByFirstAnyAllSumAverageMinMaxCountTakeSkipTakeWhileSkipWhileDistinctReverseConcatZipUnionIntersectExceptSequenceEqualToArrayToListToDictionaryRangeRepeat、およびそれらの連結。LINQ や List<T>Array のヘルパーに渡したラムダは、呼び出し箇所に展開されます。

デリゲートは ActionFunc のフィールド、Action done = Cleanup; のようなメソッドグループ、マルチキャストの +=-=、C# の event 宣言、他のビヘイビアの public メソッドへのデリゲートです。ラムダは値として使えます。変数をキャプチャするラムダには一つだけ制約があり、後述します。文字列には FormatSplitJoinSubstringReplaceTrimPadLeft があります。null 許容値型には HasValueGetValueOrDefault があります。enum には ParseTryParseGetNamesGetValuesHasFlag があり、typeof(T).Name もコンパイルできます。throw はメッセージをログに出してビヘイビアを停止するので、アサーションとして使えます。捕まえるものはありません。直接の再帰と相互再帰はコンパイルでき、呼び出しの前後でメソッドの変数がスタックに退避されます。

Unity と VRChat

コンポーネントの取得 InstantiateDestroy Transform と物理 Mathf と値型 RandomTime コルーチン Invoke asyncawait VRCPlayerApi Networking ピックアップとステーション UdonBehaviour の参照 他のビヘイビアの Unity メンバー Unity と SDK の型の配列 Unity オブジェクト型どうしのキャスト

コンポーネントの取得は GetComponent<T>() とその派生、非ジェネリックの GetComponent(typeof(T))TryGetComponent<T>(out T)、それに SetActive です。値型は Vector3QuaternionColor をはじめとする一般的な Unity の構造体です。コルーチンは yield return nullWaitForSecondsWaitUntil、入れ子のコルーチンを使え、StartCoroutine(Run())StartCoroutine(nameof(Run)) で開始し、StopCoroutine(handle)StopAllCoroutines で停止します。InvokeInvokeRepeatingCancelInvoke は public メソッドに使えます。async メソッドは voidTaskUniTaskUniTaskVoid を返せます。await Task.Delay(...) や他の async メソッドの await も可能です。UdonBehaviour の参照では SendCustomEventSetProgramVariableGetProgramVariable<T> が使えます。他のビヘイビアの gameObjecttransformenabled は直接読み書きできます。Unity の型、コンポーネント、SDK の enum の配列は、他のフィールドと同じように使えます。ネットワークにあるものすべて。

シェーダーとマテリアルへの書き込み

VRCShader のグローバル material.SetFloat など MaterialPropertyBlock EnableKeyword

UnityEngine.Shader は公開されていません。グローバルは VRCShader.PropertyToID(name)VRCShader.SetGlobalFloatSetGlobalVectorSetGlobalColorSetGlobalMatrixSetGlobalTexture、そしてそれぞれの配列版を使います。SetGlobalInt はありません。SDK が持っていないからです。

グローバルの名前は _Udon で始めなければなりません。 そうでないものを VRChat は無視します。しかも黙って無視します。 呼び出しは成功し、シェーダーは古い値のまま、ログには何も出ません。グローバルはマテリアルのプロパティではないので、 シェーダー側では Properties ブロックの外で宣言してください。

マテリアルのプロパティは普通に扱えます。名前でも id でも SetFloatSetColorSetVectorGetColor、 それに MaterialPropertyBlockEnableKeywordmaterial ではなく sharedMaterial を使ってください。 material に触れると実行時にマテリアルが複製され、実行時マテリアルはシーンディスクリプタに登録しない限り ビルドから取り除かれます。

2026-09-08、コンパイルだけでなくアップロードしたワールドで両方の経路を確認済みです。

Udon が決して実行できないもの

これらは UDN0011 で拒否されます。拒否のメッセージがその旨と、代わりにどうすべきかを示します。

構文 理由と、代わりに書くこと
catch Udon には捕まえる例外がありません。フォルトはビヘイビアを停止します。catch を外し、先に条件を確認してください。tryfinally はコンパイルでき、throw はメッセージをログに出してビヘイビアを停止します。
書き換え可能な static フィールド ビヘイビアごとに独立したヒープを持つため、static は「共有された一つの値」ではなく「ビヘイビアごとに一つの値」になってしまいます。どれか一つのビヘイビアのフィールドを参照する形にするか、記憶領域を持たない get 専用の static プロパティを使ってください(シングルトン)。
AwakeResetOnValidateOnGUIOnDrawGizmosOnApplicationQuitOnApplicationPauseOnApplicationFocusOnAudioFilterRead Udon はディスパッチしません。Awake の処理は Start に移してください。残りはエディタ専用か、ワールドではなくアプリケーションのためのものです。OnApplicationQuit で意図していたのは、たいてい OnPlayerLeft です。
CompareTaggameObject.tagFindGameObjectWithTag Udon はタグを公開していません。レイヤーや名前を比べるか、参照を持つか、GameObject.Find を使ってください。
Camera.main 公開されていません。インスペクタでカメラをフィールドに割り当ててください。
SendMessageIsInvoking、その他 Udon にない MonoBehaviour のメンバー コルーチン、InvokeCancelInvoke は Udonite が変換します。それ以外にはワールドで動く形がありません。
Application.isPlayingisFocusedtargetFrameRateplatformTime.timeScaleAudioListener 公開されていません。ワールドは常に実時間で再生中です。VR かデスクトップかは Networking.LocalPlayer.IsUserInVR() で判定し、リスナーではなく各 AudioSource を設定してください。
PlayerPrefsResources.LoadSceneManagerUnityEventShaderInput.mousePositionnew GameObject()GameObject.CreatePrimitiveMesh.CombineMeshesTMP_Text.SetText それぞれの拒否メッセージが VRChat 流の書き方を示します。永続化は PlayerData、アセットはインスペクタのフィールド、シーン読み込みの代わりに VRCPlayerApi.TeleportToUnityEvent の代わりにインスペクタで結線した public メソッド、グローバルなシェーダープロパティは VRCShader、ポインタの代わりに頭のトラッキングデータ、生成はプレハブかテンプレートオブジェクト、メッシュはエディタで結合、そして text プロパティです。
素のオブジェクト(ビヘイビアでないもの)のメソッドを指すデリゲート、および Unity がシリアライズする public フィールドに置いたデリゲート どちらもワールドまで持ち込めません。
生成したメソッドの外まで持ち越すキャプチャ付きラムダ(フィールドへの代入、戻り値、引数として渡す) キャプチャした変数はビヘイビアの単一のヒープにあるため、保存したクロージャは次の呼び出しで古い状態を見てしまいます。キャプチャしないラムダは自由に保存できます。キャプチャするものは、同じメソッド内で呼ぶローカルとしてなら動きます。
checked 演算 Udon の演算子 extern はオーバーフローで例外を出さず、そもそも Udon には投げる例外がありません。演算の前にオペランドを確認してください。
このプログラムがコンパイルするクラスを型に持つフィールド(配列も含む)を、インスペクタでシリアライズすること インスタンスはプログラムの実行中にしか存在しないため、Unity にはインスペクタに出すものも保存するものもなく、そのフィールドは空のままワールドに届きます。private にするか [NonSerialized] を付けて、Start で埋めてください。これはフィールドの話であって型の話ではありません。クラス自体はローカル変数、引数、private フィールドとしては問題なく使えます。プリミティブ、Unity の型、SDK の enum、ビヘイビア参照のフィールドや配列も問題ありません。
デリゲートを経由する再帰(UDN0012 直接の再帰と相互再帰はコンパイルできます。デリゲート呼び出しを含む循環には退避先を決められる呼び出し先がないため、循環の中ではメソッドを直接呼んでください。

まだ対応していないもの

UDN0002 で拒否されます。これは Udon ではなく Udonite 側の不足で、要望のあったものから解除されていきます。

  • ループ内で宣言したキャプチャ付きラムダ。

拒否で行き詰まったら、その拒否の行を添えて Issue を立ててください。名前さえ分かれば、たいてい一日ほどで対応できます。

問題が発生しました 再読み込み