tolua踩坑(一)

这几天整了一下lua,打算以此增加demo的灵活度,为以后实现热更新做准备。框架采用tolua,这框架该有的都有,但用起来就是没有Spring等等大型的框架好用,且其中的坑比之Spring有过之而无不及,简直梦回初学Spring的时候,一个问题能捣鼓一天,最后发现其实简单的不得了。这个系列的博客就来记录下我踩的tolua坑,避免以后再掉到相同的坑里。


1. 句号(.)和冒号(:)

我记得之前看见有人说过这个事,但我真正遇到的时候却忘了这茬。
tolua在向LuaState注入我们指定的类型后,调用方式一般是和在C#中一样的,类似于

instance = Thunder.UI.BaseUi()

这样的调用(为什么Markdown连lua的高亮都没有??果然lua还是太小众了么,还是Notepad兼济天下),一般来说没什么问题,命名空间、类、属性等都是和C#一样通过句号(.)来获取,但是方法就不一样了,我们知道,方法是有静态和非静态之分的,通过static修饰符来区分。C#、Java等语言调用时都一视同仁,使用(.)来获取。lua则比较标新立异,非静态用(:),静态则用(.)。举个例子:

namespace Thunder.Vehicle
{
	public class BattleShip
	{
		public static void Shoot()
		{
			Debug.Log("Shoot");
		}
		
		public void Person Invade()
		{
			Debug.Log("Create Person");
			return new Person()
		}
	}
	
	public class Person
	{
		public static void Melee()
		{
			Debug.Log("Melee!!");
		}
	}
}

这个类被注入了lua的环境,那么需要按如下方式调用:

battleShip = Thunder.Vehicle.BattleShip()
battleShip.Shoot()
battleShip:Invade().Melee()

-- Output:
--
-- Shoot
-- Create Person
-- Melee!!

可见BattleShip对它的静态方法Shoot使用(.)调用,对非静态方法Invade使用(:)调用。返回的Person使用(.)调用它的静态方法Melee。此外Thunder.Vehicle.BattleShip也使用(.)来进行命名空间的选择。


2. 泛型

tolua对于泛型的支持可谓是十分稀烂,不过对于lua来说,或许本来也就没有什么好的方法来让它适配泛型,因为它本身就是弱类型的语言。但又要与C#这种强类型的语言进行交互,还是有处理这方面的必要的。先提个需求,看看tolua怎么处理这事:

有战舰(BattleShip)和人类(Person)两种对象,我们需要让战舰通过某种方式接收士兵。具体的实现方式是,在lua文件中定义一个方法,返回人类的list。类的定义如下:

namespace Thunder.Entity
{
	public class BattleShip
    {
        public LuaState luaState;

        private List<Person> _Marine;

        public void ReceiveSoldiers()
        {
            _Marine = luaState.Invoke<List<Person>>("ReceiveSoldiers",true);
        }
    }

    public class Person
    {
        public int Id;

        public Person(int id)
        {
            Id = id;
        }
    }
}

重点,需要向CustomSettings.cs中的customTypeList添加:

_GT(typeof(System.Collections.Generic.List<Person>)),
_GT(typeof(Thunder.Entity.BattleShip)),
_GT(typeof(Thunder.Entity.Person))

泛型类型是不能单独使用的,需要按照特例来添加。这就使得泛型这种优雅的语法完全迟钝化,不过这也是没办法的事。接下来是lua:

function ReceiveSoldiers()
    soldiers = System.Collections.Generic.List_Thunder_Entity_Person()
    for id=0,300,1 do
        soldiers:Add(Thunder.Entity.Person(id))
    end
    return soldiers
end

可以看见,lua创建list对象时使用的名称是List_Thunder_Entity_Person,看到这里,大家应该很快就能发现:在lua中调用tolua包装好的泛型类,需要将(.)转换为(_),如果有多个类型参数,需要依次排列,顺序不能颠倒,而且需要使用FullName,也就是包含了namespace的名称,例如List_Thunder_Entity_Person_Thunder_Entity_BattleShip,不能省略namespace。
鉴于这种情况,我的解决方案就是设计接口的时候,能不用泛型就不用,尽量使用传统的语法来完成需求。不过吃惯了C#甜味十足的语法糖,现在要转换成这种死板的语法,实在是有些不适应。

你可能感兴趣的:(踩坑记录,lua,c#)