Language support
What compiles today, and the parts of C# that Udon can never run.
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-genericGetComponent(typeof(T)).- Recursion (
UDN0012), capturing lambdas inside loops,checkedarithmetic.
If a refusal blocks you, open an issue with the refusal line. The construct is usually a day's work once it is named.