在.net使用lua——(二)NLua在.net开发过程中的使用

本文介绍了如何在.NET项目中集成和使用NLua,包括安装包、设置编码、执行Lua脚本、处理中文、计算表达式、.NET值与Lua交互、Lua函数调用以及.NET对象传递。重点讲解了如何解决.NET数组在Lua中的使用问题和提供动态曲线绘制功能的实例。
摘要由CSDN通过智能技术生成

由于之前几天一直在忙于之前软件功能的修改和bug修复,所以一直没有更新,今天正好有空,补充一下lua在.net中使用的第二篇,这篇文章会比较长,将原本两篇的内容合并到此篇。

Lua本身就是一个嵌入式语言学习曲线很低,假如您曾使用过python或者php之类的编程语言,通过一个小时左右的学习就可以掌握此语言。在此我将不会介绍Lua语言的详细语法——推荐看一下Lua 教程 (w3schools.cn),将在此讲述一下NLua的真实使用体验。

首先安装NLua包到项目中

dotnet add package NLua

你的软件现在可以启用NLua的环境,通过lua命令的字符串给程序带来灵活响应用户需求变更的能力了。

NLua使用的具体API可以参考官方在github中的文档,NLua官方文档,文档非常详细的使用了nlua中的使用。

让NLua支持中文,请将其编码格式转换为UTF-8

using (Lua lua = new Lua())
{
	lua.State.Encoding = Encoding.UTF8;
	lua.DoString("res = 'Файл'");
	string res = (string)lua["res"];

	Assert.AreEqual("Файл", res);
}

创建Lua环境

	using NLua;
	
	Lua state = new Lua ()

计算简单表达式

var res = state.DoString ("return 10 + 3*(5 + 2)")[0] as double;

执行结果将返回一个数组,需要根据语义,将运行结果转换为对应的.net值类型实例。

将.net值传递给状态:

	double val = 12.0;
	state ["x"] = val; // Create a global value 'x' 
	var res = (double)state.DoString ("return 10 + x*(5 + 2)")[0];

检索全局值:

	state.DoString ("y = 10 + x*(5 + 2)");
	double y = (double) state ["y"]; // Retrieve the value of y

通过索引器,可以访问到Lua中已经存储的对象,对象可以是值对象,也可以是array或者table

检索 Lua 函数:

	state.DoString (@"
	function ScriptFunc (val1, val2)
		if val1 > val2 then
			return val1 + 1
		else
			return val2 - 1
		end
	end
	");
	var scriptFunc = state ["ScriptFunc"] as LuaFunction;
	var res = (int)scriptFunc.Call (3, 5).First ();
	// LuaFunction.Call will also return a array of objects, since a Lua function
	// can return multiple values

通过索引器访问Lua函数,并通过Call调用此函数。同时Lua中的函数也是一个变量,因此上面的ScriptFunc函数也可以如此访问。Call调用函数返回的也是一个数组,可以通过对数组元素的访问,获取返回值。

	state.DoString (@"
	scriptfuncval = function ScriptFunc (val1, val2)
		if val1 > val2 then
			return val1 + 1
		else
			return val2 - 1
		end
	end
	");
	var scriptFunc = state ["scriptfuncval"] as LuaFunction;
	var res = (int)scriptFunc.Call (3, 5).First ();
	// LuaFunction.Call will also return a array of objects, since a Lua function
	// can return multiple values

将 .NET 对象传递给状态:

	SomeClass obj = new SomeClass ("Param");
	state ["obj"] = obj; 
    // Create a global value 'obj' of .NET type SomeClass 
	// This could be any .NET object, from BCL or from your assemblies
    

假如SomeClass有一个函数SomeFunction(int i),那么在Lua中调用此函数如下:

state.DoString("res=obj:SomeFunction(1)")

加入SomeClass有一个静态函数StaticFunction(int i),在Lua中如下调用:

state.DoString (@"local res4 = SomeClass.StaticMethod(4)");

local代表是本地变量,使用了local前缀的变量,不能通过NLua的索引器在.net语句中进行访问。

接下来我们来看一个真实案例中NLua中的应用。

在开发过程中,我们遇到了这样一个问题,用户希望绘制一条曲线,这条曲线的x坐标值,可以需要根据给出的公式进行计算。这样我们就需要提供给客户一个接口,让他通过输入一个表达式,随时改变曲线的绘制方式。

需求如下,取一段时间的值,再通过输入的多项式拟合计算出x坐标值。可能的公式:

res=avg(arr)^3*a+avg(arr)^2*b+avg(arr)*c+d

也可能是:

res=max(arr)*2*10+3

 此时,我们引入NLua可以很轻松的通过将决定权给用户来实现这个需求。在此处,有两个知识点需要说明:lua的math库,以及.net的数组如何在lua中访问。

lua中引入math库

state.DoString(@"math=require 'math'")
state.DoString(@"math.max(arr)")

.net数组对象赋值给lua对象并不能正常的当作lua数组进行访问,在table.unpack的解包过程中会抛出异常。

double[] vals = new double[5] { 1, 2, 3, 4, 5 };
state["arr"] = vals;
state.DoString(@"math=require 'math'
                maxVal=math.max(table.unpack(arr))");
var obj = state["maxVal"];

//thorw exception attempt to get length of a System.Double[]

查看了官方的案例,并没有给出解决方案,可能是一个BUG。我提交了一个issue给到list,目前没有收到官方的回复。

我为Array添加了扩展函数ToLuaTable,

public static class ArrayExtensions
    {
        public static NLua.LuaTable ToLuaTable(this Array array, Lua state, string name)
        {
            state.DoString(name + "={}");
            LuaTable table = state.GetTable(name);
            for (int i = 0; i < array.Length; i++)
            {
                table[i] = array.GetValue(i);
            }
            return table;
        }
    }

通过它,我将.net数组转换成了Lua数组,这样就可以执行函数过程中得到预期结果了。

double[] vals = new double[5] { 1, 2, 3, 4, 5 };
vals.ToLuaTable(state,"arr");
state.DoString(@"math=require 'math'
                maxVal=math.max(table.unpack(arr))");
var obj = state["maxVal"];

如果我的文章对您有所帮助,请您为我的文章点赞,让更多人可以看到,谢谢。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值