Maintaining Visibility

There is a difference between a type being visible to Lua code and registering a type. If a method returns an object, it can be used within Lua even if the type is not registered. When you register a type with Lua, you give access to two things: (1) the visible constructors, and (2) the visible static members. An object that is returned from a method is not affected by whether it is registered. By default, all public members of types are visible to Lua code. Also, optionally the framework will respect return types by making only the public members of the returned type visible. There are two ways to change this behavior: LuaIgnoreAttribute, and LuaUserData. If there is a conflict, a member will not be visible.

Example (if StringBuilder is registered):

-- create an instance to type StringBuilder
sb = StringBuilder()

-- call an instance member.

-- access a static field.
-- notice that both syntax for member access is valid for .NET types ONLY.



LuaIgnoreAttribute is used to control visibility for all variables of a given type. This is an attribute that can be attached to a member or type to alter what members are visible. The exact behavior depends on what the attribute is attached to and what arguments are passed.  This attribute is inherited.

When LuaIgnoreAttribute is attached directly to a member, the given member is not visible to Lua code. There is no way to modify this behavior. Any arguments passed to the attribute will be ignored. If this is attached to a member of an interface, than it will only have affect if the type is behaving-as the given type.

If the attribute is attached to a type there are several cases that it can be depending on the arguments that are passed. If the class is inherited, this attribute will come with it, however it can be overridden by attaching the attribute to a derived class. If the sole argument is 'true' then it behaves the same as no arguments. This means that none of the members will be visible. If it is 'false' then all members are visible (same as without the attribute). If the sole argument is a Type object, then a variable of this type will behave-as the given type.

You can change the behavior beyond these defaults. To start, call the constructor with 'false' as the first argument. Then you can add members either to AccessMembers or IgnoreMembers. If AccessMembers is not null, a member must be in that array to be visible. If IgnoreMembers is not null, then a member must not be in that array to be visible. If DefinedOnly is true, than only members that are explicitly defined in this type are visible. If BehavesAs is not null, than the type will behave-as the given type.


LuaUserData is a special variable type that is used to control visibility for a single variable. There are two versions of this type, the generic and non-generic versions. The generic version derives from the non-generic version and only the non-generic version is used internally. The generic version should be used by users to ensure type-safety with arguments. When a variable is passed back to Lua code, it sometimes is stored as a LuaUserData variable. If a variable is passed to Lua through a return value or a by-reference argument, then it is usually stored in a LuaUserData variable to ensure that it is treated as the given type.

When a LuaUserData object is passed as an argument to a function, it is valid to convert it to it's backing type. However, it may be helpful to accept a variable of type LuaUserData to ensure that the visibility rules are not lost or violated. The generic version ensures that a variable of the given type is passed. The non-generic version is the same as accepting a variable of any type (type object).

The behavior of this object is the same as for LuaIgnoreAttribute, except that it is fora single variable. Also, there is a field called CanPass, This ensures that special variables are not passed back toC# code.


Behaves-as is used in both LuaUserData and in LuaIgnoreAttribute. This means that a variable or type will behave as if it was the given type. This is the same as storing a variable of one type in a variable of a base type or interface. This is used in LuaUserData to ensure that Lua cannot violate accessibility when return types do not match the backing object type. This can also be used with LuaIgnoreAttribute when attached to a type. This means that variables of that type always behave as if they were the given type. This can be used if you define a class as the default implementation of an interface that you want to expose to Lua. The default environment is marked in this way to ensure that Lua cannot access the method on DynamicObject.

When an object is behaving as another type, that other type entirely defines what members are visible to Lua. The members are still invoked virtually, however new members defined in the derived type will not be visible. When a member of an interface is marked with LuaIgnore, it does not effect the visibility of that member unless the type is behaving as the interface type. This is because attributes are not inherited from interfaces unless the member is implemented explicitly and that would mean that the member is not public and then cannot be accessed by Lua.


public class Class1
     // visible to Lua
     public Class1()

     // not visible to Lua
     public void Some()

     public LuaUserData Some2()
           // returns a StringBuilder object that only has the 'Append' member visible
           return new LuaUserData(new StringBuilder(), "Append");

// none of the members of this type will be visible [LuaIgnore] public class Class2 { }

Last edited May 26, 2013 at 3:26 AM by ModMaker, version 5


No comments yet.