【问题标题】:Mapping C# classes to Lua functions via dll通过 dll 将 C# 类映射到 Lua 函数
【发布时间】:2012-11-07 03:44:06
【问题描述】:

在我的“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 环境中的重建版本可能会有所帮助。

【问题讨论】:

  • 我在使用 LuaInterface 时遇到了一些实际问题。您可能想查看 C# Compiling on the fly。
  • @Ruirize 感谢您的评论。那些“真正的问题”让你最终放弃了这种方法吗?我将看看 C# Compiling on the fly。希望不复杂。
  • 基本上,如果没有长时间的变通方法,我无法将我的 C# 类公开给 Lua,这会使生成的 Lua 代码非常难看。 (我已经失去了这个项目,这是不久前的事了)C# 编译非常简单,你可以通过使用访问修饰符来控制暴露的内容。
  • 问题是在这件事上我们必须坚持Lua。故事是,我们有一个用 Lua 编写的相当复杂的 ToolBox,现在我们想迁移到 .NET 框架。但是工具箱中的所有方法仍然必须像以前的好方法一样可以在 Lua 脚本中访问。这就是 LuaInterface 发挥作用的地方。但是,它不适用于此特定应用程序。
  • 祝你狩猎愉快,好运。

标签: c# .net lua luainterface


【解决方案1】:

所以我也花了很多时间。真正让我发疯的是试图让 Enums 工作。最终我放弃了我的项目,转而使用一个非常简单的控制台应用程序,非常相似(具有讽刺意味的是,它也被命名为“LuaTest”)。

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

另一个编辑:正如我在下面编辑错误的评论中,当我删除时:

print(luanet.LuaTest.Pointless)

这一切都停止了(LuaTest.Pointless 变成了 nil)。但是添加 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'

【讨论】:

  • 很好奇。我今天正在处理这个问题,弄乱了 CLR 对象的子类。在我删除该行之前,调用子类(PointlessTwo)上的项目一直有效:print(luanet.LuaTest.Pointless) 当我删除该行时它停止工作。但是添加 luanet.load_assembly("LuaTest") 使它再次工作! print(luanet.LuaTest.Pointless) 是否存在某种隐式负载?我想知道。
【解决方案2】:

在过去的几天里,我在一个需要 LuaInterface 的确切功能的项目上工作,我偶然发现了一段 Lua 代码,结果证明它是完美的解决方案(请参阅参考资料 1)。在寻找这个解决方案时,我注意到了这个问题,并认为我会投入两分钱。

要应用此解决方案,我只需在初始化 LuaInterface Lua 对象时运行 CLRPackage 代码。但是,require 语句也同样有效。

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

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/

【讨论】:

    【解决方案3】:

    我花了一些时间将 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!");
            }
        }
    }
    

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

    生成的 DLL 的位置需要 lua 环境知道。将其粘贴到例如“clibs”文件夹或另一个众所周知的 lua 系统路径中。然后尝试使用下面的 lua 示例。它应该可以工作。

    Test1.lua:(选项 1,从 CLRPackage 中“导入”)

    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:(带有“load_assembly”的选项2)

    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
    Constructor 2
    无名
    火星
    地球是我的家乡。它的直径约为12742公里。我们的邻居是火星

    希望对大家有所帮助。

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

    PlanetObject1:testMethod()
    PlanetObject2:testMethod()
    

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

    【讨论】:

      猜你喜欢
      • 2013-10-18
      • 2011-12-07
      • 2020-05-16
      • 1970-01-01
      • 2012-02-13
      • 1970-01-01
      • 1970-01-01
      • 2011-06-01
      • 2016-08-08
      相关资源
      最近更新 更多