Skip to content

.NET Bindings

Kevin Zhao edited this page Jan 25, 2018 · 4 revisions

.NET Bindings

Bindings to .NET objects are achieved using userdata with metamethods that emulate typical C# access of the .NET object. Objects are stored using strong GCHandles, preventing the .NET GC from garbage collecting them. This approach obviates the need of assigning each object a unique ID and performing a lookup for every access.

Member Access

The members of a .NET object or static members of a .NET type are accessed using the __index metamethod. In particular, methods will return a function which can be called at a later time, events will return a wrapper object that handles event subscription and unsubscription, and indexed properties will return a wrapper object that handles getting and setting. These special results are cached to improve performance.

One-dimensional arrays are also accessed in the same manner. Multi-dimensional arrays must be accessed using the GetValue function.

Method Calls

Method calls will ignore out parameters for the purpose of input validation, and will return ref and out parameters as extra return values. Generic method calls are handled by returning another function if the original attempt to call the method fails! In particular, the following declaration can be problematic:

void Method<T>();
void Method(Type t);

The second method will always be called with the Method(type) syntax, making it impossible to call the first method whatsoever. This can theoretically be resolved by using reflection from within Lua, but this edge case is rare enough in the first place.

Member Modification

The members of a .NET object or static members of a .NET type are modified using the __newindex metamethod.

One-dimensional arrays are also modified in the same manner. Multi-dimensional arrays must be modified using the SetValue function.

Calling

If a .NET object is a Delegate, then it can be called using the __call metamethod. A .NET type can also be instantiated using the __call metamethod, and if it is a generic type, then it will return a constructed generic type which can then be instantiated.

Operators

The operators of a .NET object are implemented using the various operator metamethods. In particular, both operands of a binary operation will be checked for an operator that satisfies the given signature! This deals with the following edge case:

public class Test1 {
    public static int operator +(Test2 t2, Test1 t1);
}
public class Test2 {
    public static int operator +(Test2 t2, int i);
}

lua["t1"] = new Test1();
lua["t2"] = new Test2();
lua.DoString("x = t2 + t1");
Clone this wiki locally