Asignación de clases de C#a las funciones de Lua a través de dll
.net luainterface (3)
En mi espacio de nombres "LuaTest" tengo una clase llamada "Planet". El código de C # se lee así:
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);
}
}
}
Luego construí LuaTest.dll y copié este archivo en la misma carpeta donde está guardado mi script Lua. En el script de Lua, escribí:
--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()
Sin embargo, esta pieza de código no funciona. El intérprete de Lua arroja este error:
lua: dllTest.lua:7: attempt to call local ''Planet'' (a nil value)
Sospecho que mi ensamblaje LuaTest no está cargado en absoluto. ¿Alguien podría señalar dónde hice mal? Lo agradecería mucho, ya que he estado atrapado por este problema por días.
También podría ser útil agregar que mi LuaInterface.dll es la versión reconstruida en el entorno .NET4.0.
Así que pasé MUCHO tiempo de manera similar. Lo que realmente me ha vuelto loco fue intentar que Enums funcionara. Eventualmente abandoné mi proyecto por una aplicación de consola muy simplificada, muy similar (irónicamente también llamada ''LuaTest'').
Editar: he notado que el "luanet.load_assembly" ("LuaTest") inicial parece superfluo. Funciona con él, o sorprendentemente sin él.
Otra edición: como en mi comentario mal editado a continuación, cuando eliminé:
print(luanet.LuaTest.Pointless)
Todo dejó de funcionar (LuaTest.Pointless se volvió nulo). Pero agregar luanet.load_assembly ("LuaTest") lo hace funcionar. Puede ser que exista algún tipo de carga implícita impar en la impresión o que simplemente expresen su tipo. Muy extraño (tm).
En cualquier caso, parece funcionar para mí (nota: después de mucha experimentación). No sé por qué el suyo está fallando, no noto ninguna diferencia real, pero aquí está todo mi código en caso de que alguien más pueda detectar la diferencia crítica:
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.");
}
}
}
y 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''
Después de haber pasado los últimos días trabajando en un proyecto que requería esta funcionalidad exacta de LuaInterface, me topé con una parte del código Lua que resultó ser la solución perfecta (ver referencia 1). Mientras buscaba esta solución, noté esta pregunta y pensé que dejaría caer mis dos centavos.
Para aplicar esta solución, simplemente ejecuto el código CLRPackage al inicializar mi objeto Lua LuaInterface. Sin embargo, la declaración require funciona igual de bien.
El código provisto en la referencia 1 permite el uso de declaraciones de importación, similar a C # using statements. Una vez que se importa un ensamblaje, se puede acceder a sus miembros en el espacio de nombres global. La instrucción de importación elimina la necesidad de usar load_assembly o import_type (excepto en situaciones en las que necesite utilizar miembros del mismo nombre de diferentes ensamblados. En este escenario, import_type se usaría de manera similar a C # utilizando NewTypeName = Assembly.OldTypeName).
import "LuaTest"
planet = Planet("Earth")
planet:printName()
¡Este paquete también funciona muy bien con enums!
Se puede encontrar más información sobre el uso de este paquete en la Referencia 2.
¡Espero que esto ayude!
Referencia 1: https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua Referencia 2: http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/
Pasé algún tiempo enlazando C # dll a lua. Tus publicaciones fueron útiles, pero faltaba algo. La siguiente solución debería funcionar :
(¡Asegúrese de cambiar su compilador a .NET Framework 3.5 o inferior!)
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!");
}
}
}
Use el código anterior, péguelo en su proyecto de biblioteca de clase y compílelo con .NET menor o igual a 3.5.
La ubicación de la DLL generada debe ser conocida por el entorno lua. Pégalo, por ejemplo, en la carpeta "clibs" u otra ruta conocida del sistema lua. Luego intente usar el siguiente ejemplo de lua. Deberia de funcionar.
Test1.lua: (Opción 1 con "importación" desde 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: (Opción 2 con "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)
En ambos casos, la salida de la consola se verá así:
ProxyType (Planets.Planet): 18643596
Constructor 1
Planetas.Planet: 33574638
Constructor 2
sin nombre
Marte
El planeta Tierra es mi planeta de origen. Su diámetro es alrededor de 12742 km. Nuestro vecino es Marte
Espero que sea de ayuda para algunos de ustedes.
Edición 1: por cierto, una llamada a un método de lua se ve así:
PlanetObject1:testMethod()
PlanetObject2:testMethod()
Editar 2: encontré diferentes dll que necesitaban manejarse de manera diferente. Uno necesitaba la función de "importación" y otro necesitaba la función "cargar_ensamblaje". Mantenga eso tal vez en mente!