通过dll将C#类映射到Lua函数
在我的“LuaTest”名称空间中,我有一个名为“Planet”的类。C代码如下所示:通过dll将C#类映射到Lua函数,c#,.net,lua,luainterface,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) {
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);
}
}
}
PlanetObject1:testMethod()
PlanetObject2:testMethod()
然后我构建了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环境中重建的版本可能会有所帮助。因此我也花了很多时间。真正让我发疯的是试图让enum正常工作。最终,我放弃了我的项目,转而开发了一个非常简单的控制台应用程序,非常类似(讽刺的是,它也被命名为“LuaTest”) 编辑:我注意到最初的“luanet.load_assembly(“LuaTest”)”看起来是多余的。可以使用它,也可以不使用它 另一个编辑:如我下面编辑不好的评论,当我删除时:
print(luanet.LuaTest.Pointless)
一切都停止了(LuaTest.imponent变成了零)。但是添加luanet.load_程序集(“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'
在过去的几天里,我一直在从事一个需要LuaInterface提供这一功能的项目,我偶然发现了一段Lua代码,这是一个完美的解决方案(参见参考文献1)。在寻找这个解决方案时,我注意到了这个问题,我想我应该把我的两分钱投进去 要应用此解决方案,我只需在初始化LuaInterface Lua对象时运行CLRPackage代码。然而,require语句也同样有效 参考文献1中提供的代码允许使用导入语句,类似于C#using语句。导入程序集后,可以在全局命名空间中访问其成员。import语句消除了使用load_assembly或import_type的需要(需要使用来自不同程序集的同名成员的情况除外。在这种情况下,import_type将类似于C#使用NewTypeName=assembly.OldTypeName) 这个软件包也适用于Enum 有关使用该包装的更多信息,请参见参考文献2 希望这有帮助 参考文献1:
参考文献2:我花了一些时间将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的版本编译
lua环境需要知道生成的DLL的位置。例如,将其粘贴到“clibs”-文件夹或其他众所周知的lua系统路径。然后尝试使用下面的lua示例。它应该会起作用
Test1.lua:(带有“从CLR包导入”的选项1)
Test2.lua:(带有“加载组件”的选项2)
在这两种情况下,控制台输出如下所示:
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);
}
}
}
PlanetObject1:testMethod()
PlanetObject2:testMethod()
ProxyType(行星:18643596构造函数1
行星。行星:33574638
构造函数2
无名的
火星
地球是我的家园。它的直径约为12742公里。我们的邻居是火星 我希望这对你们中的一些人有所帮助 编辑1: 顺便说一下,lua的方法调用如下所示:
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);
}
}
}
PlanetObject1:testMethod()
PlanetObject2:testMethod()
编辑2:
我发现需要以不同的方式处理不同的dll。一个需要“导入”功能,另一个需要“加载组件”功能。记住这一点 当我使用LuaInterface时,我在这方面遇到了一些实际问题。您可能想研究C#动态编译。@谢谢您的评论。你让你最终放弃这种方法的那些“真正的问题”吗?我将看一看C#动态编译。希望不会太复杂。基本上,如果没有长时间的解决方案,我无法将我的C#类公开给Lua,这会使生成的Lua代码非常难看。(我已经失去了这个项目,这是很久以前的事了)C#编译非常简单,你可以通过使用访问修饰符来控制暴露的内容。问题是在这件事上我们必须坚持使用Lua。故事是,我们有一个用Lua编写的相当复杂的工具箱,现在我们想迁移到.NET framework。但是,工具箱中的所有方法仍然必须像旧方法一样,在Lua脚本中可以访问。这就是LuaInterface发挥作用的地方。但是,它在这个特殊的应用程序中不起作用。祝您狩猎愉快,并祝您好运。好奇。我今天正在处理这个问题,处理CLR对象的子类。调用子类上的项(PointlessTwo)一直在工作,直到我删除该行:
print(luanet.LuaTest.Pointless)
当我删除该行时,它停止工作。但是添加luanet.load_assembly(“LuaTest”)使它再次工作!打印是否存在某种隐式负载(luanet.LuaTest.Pointless)?我想知道。