通过dll将C#类映射到Lua函数

时间:2012-11-19 08:32:47

标签: c# .net lua luainterface

在我的“LuaTest”命名空间中,我有一个名为“Planet”的类。 C#代码如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;

namespace LuaTest
{
    public class Planet
    {
        public Planet(string name)
        {
            this.Name = name;
        }
        public Planet() : this("NoName") { }
        public string Name
        {
            get;
            private set;
        }

        public void printName()
        {
            Console.WriteLine("This planet's name is {0}", Name);
        }
    }
}

然后我构建了LuaTest.dll并将此文件复制到保存我的Lua脚本的同一文件夹中。在Lua脚本中,我写道:

--define Path for required dlls
package.cpath = package.cpath .. ";" .. "/?.dll"
package.path = package.path .. ";" .. "/?.dll/"
require 'luanet'
luanet.load_assembly("LuaTest")
local Planet = luanet.import_type("LuaTest.Planet")
local planet = Planet("Earth")
planet.printName()

但是,这段代码不起作用。 Lua解释器抛出了这个错误:

lua: dllTest.lua:7: attempt to call local 'Planet' (a nil value)

我怀疑我的LuaTest程序集根本没有加载。谁能指出我做错了什么?我非常感激,因为我已经被这个问题困扰了好几天。

另外,添加我的LuaInterface.dll是.NET4.0环境中的重建版本可能会有所帮助。

3 个答案:

答案 0 :(得分:0)

所以我花了很多时间。真正让我疯狂的是试图让Enums工作。最终我放弃了我的项目,用于非常简化的控制台应用程序,非常相似(具有讽刺意味的是也称为“LuaTest”)。

编辑:我注意到最初的“luanet.load_assembly(”LuaTest“)”似乎是多余的。与它一起使用,或者没有它就会令人惊讶。

另一个编辑:正如我在下面编辑得很糟糕的评论,当我删除时:

print(luanet.LuaTest.Pointless)

一切都停止了工作(LuaTest.Pointless变成了零)。但是添加luanet.load_assembly(“LuaTest”)然后使它工作。可能是在打印中存在某种奇怪的隐式加载或仅仅表达它们的类型。非常奇怪(tm)。

无论如何,它似乎对我有用(注意:经过大量实验)。我不知道为什么你的失败,我没有注意到任何真正的区别,但这是我的所有代码,万一其他人可以发现关键的区别:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LuaInterface;

namespace LuaTest
    {
    public class Program
        {
        static void Main(string[] args)
            {
            Lua lua = new Lua();
            lua.DoFile("test.lua");
            }

        public int some_member = 3;
        }

    public class Pointless
        {
        public enum AnEnum
            {
            One,
            Two,
            Three
            };

        public static string aStaticInt = "This is static.";
        public double i;
        public string n = "Nice";
        public AnEnum oneEnumVal = AnEnum.One;
        private AnEnum twoEnumVal = AnEnum.Two;
        private string very;

        public Pointless(string HowPointLess)
            {
            i = 3.13;
            very = HowPointLess;
            }



        public class MoreInnerClass
            {
            public string message = "More, please!";
            }


        public void Compare(AnEnum inputEnum)
            {
            if (inputEnum == AnEnum.Three)
                Console.WriteLine("Match.");
            else
                Console.WriteLine("Fail match.");
            }
        }



    }

和test.lua:

luanet.load_assembly("LuaTest")

--Pointless is a class in LuaTest assembly
local Pointless = luanet.import_type("LuaTest.Pointless")

print(Pointless)
--Gives 'ProxyType(LuaTest.Pointless): 46104728


print(Pointless.aStaticInt)
--'This is static.'
--Fails if not static, as we expect




--Instantiate a 'Pointless'.  
local p = Pointless("Very")

print(p)
--Gives 'LuaTest.Pointless: 12289376'



--Now we can get at the items inside the Pointless
--class (well, this instance, anyway).

local e = p.AnEnum;
print(e)
--ProxyType(LuaTest.Pointless+AnEnum): 23452342
--I guess the + must designate that it is a type?

print(p.i)
--3.14

print(p.oneEnumVal)
--Gives 'One: 0'

print(p.twoEnumVal)
--Gives 'twoEnumVal'... private
--behaves very differently.


print(e.Two:ToString())
--Gives 'Two'

local more = p.MoreInnerClass()
print(more.message)
--'More, Please!'

--create an enum value here in the script,
--pass it back for a comparison to 
--the enum.
local anotherEnumVal = p.AnEnum.Three

p:Compare(anotherEnumVal)
--outputs 'Match'

答案 1 :(得分:0)

过去几天在LuaInterface上开发了一个需要这个功能的项目,我偶然发现了一段Lua代码,结果证明这是一个完美的解决方案(参见参考文献1)。在寻找这个解决方案的过程中,我注意到了这个问题,并认为我会把我的两分钱放进去。

要应用此解决方案,我只是在初始化LuaInterface Lua对象时运行CLRPackage代码。但是,require语句也可以正常工作。

参考文献1中提供的代码允许使用import语句,类似于C#using语句。导入程序集后,可以在全局名称空间中访问其成员。 import语句不需要使用load_assembly或import_type(在需要使用来自不同程序集的同名成员的情况下除外。在这种情况下,import_type将类似于使用NewTypeName = Assembly.OldTypeName的C#。) / p>

import "LuaTest"
planet = Planet("Earth")
planet:printName()

此软件包也适用于枚举!

有关使用此包装的更多信息,请参阅参考文献2。

希望这有帮助!

参考文献1:https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua 参考文献2:http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/

答案 2 :(得分:0)

我花了一些时间将C#dll绑定到lua。你的帖子很有帮助,但缺少了一些东西。 以下解决方案应该有效

(确保将编译器更改为.NET Framework 3.5或更低版本!)

<强> Planet.dll:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Planets
{
    public class Planet
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { this.name = value; }
        }

        private float diameter;
        public float Diameter
        {
            get { return diameter; }
            set { this.diameter = value; }
        }
        private int cntContinents;
        public int CntContinents
        {
            get { return cntContinents; }
            set { this.cntContinents = value; }
        }

        public Planet()
        {
            Console.WriteLine("Constructor 1");
            this.name = "nameless";
            this.diameter = 0;
            this.cntContinents = 0;
        }

        public Planet(string n, float d, int k)
        {
            Console.WriteLine("Constructor 2");
            this.name = n;
            this.diameter = d;
            this.cntContinents = k;
        }

        public void testMethod()
        {
            Console.WriteLine("This is a Test!");
        }
    }
}

使用上面的代码,将其粘贴到您的类库项目中,并使用.NET小于或等于3.5进行编译。

生成的DLL的位置需要由lua环境知道。将其粘贴在“clibs”文件夹或其他众所周知的lua系统路径上。然后尝试使用以下lua示例。它应该工作。

Test1.lua:(来自CLRPackage的“导入”选项1)

require "luanet"
require "CLRPackage"
import "Planet"
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print(  "Planet " .. 
        PlanetObject2.Name .. 
        " is my home planet. Its diameter is round about " .. 
        PlanetObject2.Diameter .. "km." .. 
        " Our neighour is " .. 
        PlanetObject1.Name)

Test2.lua:(选项2带有“load_assembly”)

require "luanet"
require "CLRPackage"
luanet.load_assembly("Planet")
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print(  "Planet " .. 
        PlanetObject2.Name .. 
        " is my home planet. Its diameter is round about " .. 
        PlanetObject2.Diameter .. "km." .. 
        " Our neighour is " .. 
        PlanetObject1.Name)

在这两种情况下,控制台输出将如下所示:

ProxyType(Planets.Planet):18643596
构造函数1
Planets.Planet:33574638
构造函数2
无名
火星
行星地球是我的家乡。它的直径约为12742km。我们的邻居是火星

我希望它可以帮助你们中的一些人。

编辑1: 顺便说一下,来自lua的方法调用如下所示:

PlanetObject1:testMethod()
PlanetObject2:testMethod()

编辑2: 我发现不同的dll需要以不同的方式处理。一个需要“导入”功能,另一个需要“load_assembly”功能。请记住这一点!