Skip to main content

Marshal model overview

:::tip Who should read this Developers who need to understand how parameters convert between C# and Lua, and when to use [LuaMarshalAs] / Opaque. For lookup tables see the Marshal cheat sheet; for ref/out practice see the Guide. :::

ZLua keeps Lua-visible Marshal semantics the same on Mono and Il2Cpp; Il2Cpp emphasizes zero GC and fast generated-code paths.

Bidirectional call paths

Default rules summary

CategoryC# → LuaLua → C#
Primitives / enuminteger / number / booleansame
stringstringstring
classClassUserDatauserdata / nil
structByValUserData or OpaqueValueStructUserData / Type(...) (tables not accepted by default)
delegateDelegateUserDatafunction or userdata
arrayArrayUserDataArrayUserData

Full table: Marshal cheat sheet.

ref / out / in (Lua → C#)

Lua does not distinguish ref/out/in; all are treated with ref semantics:

Lua argBehavior
Same-type ByValUserData (e.g. Point2D(...)) / compatible OpaqueTrue ref — C# writes back
Bare number / string / tableCopied into a temp slot — no write-back to local

Delegates from GetFunction and the delegate bridge default-Push ref/out/in as OpaqueValue (see OPAQUE); params remains unsupported.

[LuaMarshalAs] overrides

LuaMarshalTypeTypical use
UserDataForce boxed userdata (primitives, enum, string)
Bytesbyte[] ↔ Lua string
OpaqueLightUserDataTemporary struct handle on C#→Lua stack → zlua.to_user_data

Legal combinations: LuaMarshalAs reference.

Booklet index (what to read when)

TypeSpec
Overview & default tableMarshal Spec
byref / OpaqueBYREF, OPAQUE
structSTRUCT
class / referencesCLASS
Delegate / callbacksFUNCTION
Day-to-day lookupMarshal cheat sheet