Execute Lua functions and access Lua values from C# code
SolarSharp provides powerful capabilities for calling Lua functions from C# code, allowing you to leverage Lua scripts as extensible logic within your .NET applications.
The simplest way to execute Lua code is using the DoString method:
var script = new Script();// Execute Lua code and get the resultLuaValue result = script.DoString("return 2 + 2");Console.WriteLine(result.Number); // 4
// Load and execute a Lua fileLuaValue result = script.DoFile("scripts/myscript.lua");// Or load as a string firststring luaCode = File.ReadAllText("scripts/logic.lua");LuaValue result = script.DoString(luaCode);
var script = new Script();script.DoString(@" function add(a, b) return a + b end function greet(name) return 'Hello, ' .. name end");// Get the function from globalsLuaValue addFunc = script.Globals["add"];LuaValue greetFunc = script.Globals["greet"];// Call with LuaValue argumentsLuaValue sum = script.Call(addFunc, LuaValue.NewNumber(5), LuaValue.NewNumber(3));Console.WriteLine(sum.Number); // 8// Call with object arguments (automatically converted)LuaValue greeting = script.Call(greetFunc, "Alice");Console.WriteLine(greeting.String); // "Hello, Alice"
script.DoString(@" function multiply(x, y) return x * y end");LuaValue func = script.Globals["multiply"];LuaValue result = script.Call(func, 6, 7);Console.WriteLine(result.Number); // 42
LuaValue result = script.Call(someFunction);// To objectobject obj = result.ToObject();// To specific typeint number = (int)result.ToObject();string text = result.ToString();bool flag = result.Boolean;// Check type firstif (result.Type == DataType.Number){ double value = result.Number;}
You can pass registered C# objects directly to Lua functions:
[SolarSharpUserData]public class Player{ public string Name { get; set; } public int Health { get; set; }}UserData.RegisterType<Player>();var script = new Script();script.DoString(@" function healPlayer(player, amount) player.Health = player.Health + amount return player.Health end");var player = new Player { Name = "Hero", Health = 50 };LuaValue result = script.Call(script.Globals["healPlayer"], player, 25);Console.WriteLine(result.Number); // 75Console.WriteLine(player.Health); // 75 (object was modified)
Closures provide a more convenient way to call Lua functions:
script.DoString(@" function calculate(op, a, b) if op == 'add' then return a + b elseif op == 'sub' then return a - b elseif op == 'mul' then return a * b elseif op == 'div' then return a / b end end");// Get as ClosureClosure calcFunc = script.Globals.Get("calculate").Function;// Call the closure directlyLuaValue result = calcFunc.Call("mul", 6, 7);Console.WriteLine(result.Number); // 42
var script = new Script();script.DoString(@" function processConfig(cfg) print(cfg.name) print(cfg.version) return cfg.enabled end");// Create a table in C#Table config = new Table(script);config["name"] = "MyApp";config["version"] = "1.0";config["enabled"] = true;LuaValue result = script.Call(script.Globals["processConfig"], config);Console.WriteLine(result.Boolean); // true
try{ script.DoString(@" function divide(a, b) if b == 0 then error('Division by zero!') end return a / b end "); LuaValue result = script.Call(script.Globals["divide"], 10, 0);}catch (ScriptRuntimeException ex){ Console.WriteLine($"Lua error: {ex.Message}"); Console.WriteLine($"Call stack: {ex.CallStack}");}
// Using Script.CallLuaValue func = script.Globals["myFunction"];LuaValue result = script.Call(func, arg1, arg2);
Both approaches work identically. Closure.Call is slightly more direct but requires the function to be a Closure. Script.Call can also invoke CLR functions and handle callables via __call metamethods.
script.DoString(@" Person = {} Person.__index = Person function Person.new(name, age) local self = setmetatable({}, Person) self.name = name self.age = age return self end function Person:greet() return 'Hello, I am ' .. self.name end function Person:getAge() return self.age end");// Create a Person instanceClosure personConstructor = script.Globals.Get("Person").Table.Get("new").Function;LuaValue personObj = personConstructor.Call("Alice", 30);Table person = personObj.Table;// Call methods on the person instanceLuaValue greetMethod = person.Get("greet");LuaValue greeting = script.Call(greetMethod, person); // Pass person as selfConsole.WriteLine(greeting.String); // "Hello, I am Alice"LuaValue ageMethod = person.Get("getAge");LuaValue age = script.Call(ageMethod, person);Console.WriteLine(age.Number); // 30
// Bad - looks up function every iterationfor (int i = 0; i < 1000; i++){ script.Call(script.Globals["process"], i);}// Good - cache the function referenceLuaValue processFunc = script.Globals["process"];for (int i = 0; i < 1000; i++){ script.Call(processFunc, i);}
2
Reuse LuaValue Objects
Minimize allocations by reusing LuaValue instances when possible:
LuaValue[] args = new LuaValue[2];args[0] = LuaValue.NewNumber(0);args[1] = LuaValue.NewString("data");for (int i = 0; i < 1000; i++){ args[0] = LuaValue.NewNumber(i); script.Call(func, args);}
3
Batch Operations
Instead of calling Lua for each operation, batch operations when possible:
// Pass a table of items to process in one callTable items = new Table(script);for (int i = 0; i < 100; i++){ items[i + 1] = i * 2;}script.Call(script.Globals["processBatch"], items);
script.DoString(@" function transform(value) return value * 2 end");Closure luaFunc = script.Globals.Get("transform").Function;ScriptFunctionDelegate del = luaFunc.GetDelegate();// Use as a C# delegateLuaValue result = del(LuaValue.NewNumber(21));Console.WriteLine(result.Number); // 42