Skip to main content
SolarSharp provides a comprehensive interoperability system that allows seamless integration between Lua scripts and .NET CLR objects. This system enables you to expose C# classes, methods, and properties to Lua scripts with minimal configuration.

What is CLR Interop?

CLR Interop is the mechanism by which SolarSharp bridges the gap between Lua’s dynamic runtime and .NET’s statically-typed Common Language Runtime. It handles:
  • Type registration and descriptor management
  • Method and property access from Lua
  • Automatic type conversion between Lua and CLR types
  • Custom type descriptors for fine-grained control

Key Components

The interop system consists of several key components:

UserData

The UserData class is the central registry for CLR types exposed to Lua. It maintains a global registry of type descriptors and provides methods for type registration.
// Register a type for Lua interop
UserData.RegisterType<MyClass>();

// Register with specific access mode
UserData.RegisterType<MyClass>(InteropAccessMode.Reflection);

Type Descriptors

Type descriptors (IUserDataDescriptor) define how Lua scripts can interact with CLR objects. They handle:
  • Index operations (property/field access)
  • Method invocations
  • Metamethod implementations
  • Type compatibility checks

Registration Policies

Registration policies (IRegistrationPolicy) control how types are registered and whether automatic registration is allowed:
  • DefaultRegistrationPolicy - Prevents overwriting existing registrations, no auto-registration
  • AutomaticRegistrationPolicy - Allows automatic type registration on first use
  • PermanentRegistrationPolicy - Prevents type deregistration
// Set the global registration policy
UserData.RegistrationPolicy = new AutomaticRegistrationPolicy();

InteropAccessMode

The InteropAccessMode enum determines how SolarSharp optimizes member access for registered types:
// Slowest, uses reflection every time
// Saves memory if members are rarely accessed
UserData.RegisterType<MyClass>(InteropAccessMode.Reflection);

Access Modes

ModeOptimization TimingPerformanceMemory UsageUse Case
ReflectionNeverSlowestLowestRarely-used types
LazyOptimizedOn first accessGoodMediumGeneral purpose (default)
PreoptimizedAt registrationFastestHighestFrequently-used types
BackgroundOptimizedBackground threadGoodMediumLarge types, async scenarios
HideMembersN/AN/ALowestPrevent all member access
NoReflectionAllowedN/AN/ALowestCustom descriptors only
On AOT platforms like iOS, SolarSharp may automatically downgrade optimization modes to Reflection regardless of the specified mode.

Default Access Mode

You can set a default access mode for all type registrations:
// Set default to Preoptimized for better performance
UserData.DefaultAccessMode = InteropAccessMode.Preoptimized;

// Now all registrations use Preoptimized unless specified
UserData.RegisterType<MyClass>(); // Uses Preoptimized

Type Registration Methods

SolarSharp provides several ways to register types:
1

Manual Registration

Explicitly register individual types:
UserData.RegisterType<Person>();
UserData.RegisterType<Address>(InteropAccessMode.Reflection);
2

Assembly Registration

Register all types marked with [SolarSharpUserData] in an assembly:
UserData.RegisterAssembly();
3

Custom Descriptors

Provide your own descriptor for complete control:
var descriptor = new MyCustomDescriptor();
UserData.RegisterType<MyClass>(descriptor);

Checking Registration Status

You can check if a type is registered:
if (UserData.IsTypeRegistered<MyClass>())
{
    // Type is registered
}

if (UserData.IsTypeRegistered(typeof(MyClass)))
{
    // Type is registered
}
The IsTypeRegistered method only checks for exact type matches. A type may still be accessible through base class or interface descriptors even if it returns false.

Unregistering Types

Types can be unregistered, though this should be done carefully:
UserData.UnregisterType<MyClass>();
Unregistering types at runtime is dangerous and may cause errors in existing scripts. Only use this for testing or to re-register types with different configurations. Discard all loaded scripts after unregistering types.

Next Steps

Calling C# from Lua

Learn how to expose C# methods and objects to Lua scripts

Calling Lua from C#

Execute Lua functions from your C# code

UserData Types

Deep dive into UserData registration and custom types

Type Converters

Customize type conversion between Lua and CLR

Build docs developers (and LLMs) love