Language support

What compiles today, and the parts of C# that Udon can never run.

Updated 2026-09-03

Udonite compiles a large slice of everyday C#. Every construct below is covered by tests that assemble the output and run it on the real Udon virtual machine.

What compiles

Types and members

class struct interface enum nested types your own classes as fields and locals generics with constraints default interface methods properties auto-properties expression-bodied members indexers extension methods params optional parameters named arguments out / ref parameters tuples and deconstruction local functions static helper classes

Records and record structs: positional construction, with, value equality, ToString, deconstruction. Static fields must be const or readonly (see below).

Statements and expressions

if switch statements switch expressions for foreach while do break continue pattern matching type patterns is not null relational patterns property patterns when guards ?. ?? ??= string interpolation with format specifiers nameof arithmetic operators bitwise operators shift operators [Flags] enums HasFlag char arithmetic arrays multidimensional arrays ranges and indices Array.Sort Find FindAll Exists IndexOf Resize Copy Fill ConvertAll List<T> Dictionary<K,V> HashSet<T> Queue<T> Stack<T> LINQ Action / Func fields method groups multicast += / -= C# event delegates to another behaviour's method lambdas as values StringBuilder string.Format Split Join Substring Replace Trim PadLeft nullable value types HasValue GetValueOrDefault

Relational patterns look like is > 5 and < 10. Ranges and indices cover arr[^1] and arr[1..3]. LINQ works over arrays, lists and dictionaries: Select, Where, OrderBy, ThenBy, GroupBy, First, Any, All, Sum, Average, Min, Max, Count, Take, Skip, TakeWhile, SkipWhile, Distinct, Reverse, Concat, Zip, Union, Intersect, Except, SequenceEqual, ToArray, ToList, ToDictionary, Range, Repeat, and chains of them. Lambdas passed to LINQ and to List<T>/Array helpers are inlined at the call site. A method group looks like Action done = Cleanup;. Delegates to a public method on another behaviour, and lambdas as values, both compile; a lambda that captures a variable has one restriction, covered below.

Unity and VRChat

GetComponent<T>() TryGetComponent<T>(out T) Instantiate Destroy SetActive transforms physics queries Mathf Vector3 Quaternion Color Random Time coroutines yield return null WaitForSeconds WaitUntil nested coroutines StartCoroutine(Run()) StartCoroutine(nameof(Run)) StopAllCoroutines Invoke InvokeRepeating CancelInvoke async methods Task UniTask UniTaskVoid await VRCPlayerApi Networking pickups stations UdonBehaviour references SendCustomEvent SetProgramVariable GetProgramVariable<T>

Invoke, InvokeRepeating and CancelInvoke work on public methods. async methods can return void, Task, UniTask or UniTaskVoid, with await Task.Delay(...) and awaiting other async methods. Everything in Networking.

What Udon can never run

These are refused with UDN0011. The refusal says so, and says what to do instead.

Construct Why, and what to write instead
try/catch/throw Udon has no exceptions. Check the condition first.
Mutable static fields Every behaviour has its own heap, so a static would be one value per behaviour rather than one shared value. Use a field on one behaviour and reference it.
Awake Udon does not dispatch it. Use Start.
CompareTag and gameObject.tag Udon does not expose tags. Compare layers or names, or hold a reference.
IsInvoking, Application.isPlaying, Time.timeScale, AudioListener, new GameObject(), ScriptableObject subclasses Not exposed by Udon.
Serialized arrays of your own classes or structs in inspector fields Udon cannot deserialize them. Use arrays of primitives, Unity types, or references to behaviours.
A delegate pointing at a method on a plain object (not a behaviour), and a delegate in a public field Unity would serialize Neither survives the trip into a world.
A capturing lambda kept beyond the method that created it (assigned to a field, returned, passed as an argument, or created inside a loop) the captured variables live in the behaviour's single heap, so a stored closure would see stale state on the next call. Non-capturing lambdas can be stored freely; capturing ones work as locals called within the same method.

Not yet

Refused with UDN0002. These are gaps in Udonite rather than in Udon, and the ones people ask for get lifted.

  • List patterns (is [1, ..]).
  • typeof(T) as a free expression, and the non-generic GetComponent(typeof(T)).
  • Recursion (UDN0012), capturing lambdas inside loops, checked arithmetic.

If a refusal blocks you, open an issue with the refusal line. The construct is usually a day's work once it is named.

Something went wrong. Reload