首先,我不是以英语为母语的人,对于这个问题可能产生的任何沟通错误,我深表歉意。另外,不能真正理解你提出问题的一些指导方针,所以按照我对它的理解。因此,如果我违反了任何习俗,请告诉我。
背景
我一直在制作一个尝试为代码实现 xaml hot reload 之类的应用程序。由于我不能直接使用像 c# 这样的编译语言来实现它,我决定我将依赖第三方脚本语言,认为我可以在其中编写一些我的应用程序逻辑,然后更快地将其部署到设备上,因为我会只需按一个按钮即可发送代码。因此,可以将其想象为 react-native 世界中的 expo 客户端。
我决定使用 lua 作为脚本语言,不仅因为它编写代码非常简单,还因为它对 .net 有很好的绑定,当然我说的是 Nlua。而且,由于 Ironpython3 还没有准备好投入生产,老实说我有什么选择?
我面临的问题
因此,由于我必须绑定一些 xamarin.essentials 内容以使我更轻松地编写应用程序的 lua 端,因此我必须与一些具有静态方法等的对象进行交互。我认为在 Nlua 中使用静态方法会非常直观和直接,尽管到目前为止我似乎错了。
如何重现问题
- 因此,在 Visual Studio 中,创建一个 xamarin.forms 项目,随意命名,没关系。
- 接下来,将 Nlua nuget 包添加到所有项目中。它需要集成到所有这些中,因为它与某些 xamarin.forms 插件一样,依赖本机库来工作,因此需要将它们包含在适当的位置以便操作系统找到它们。当安装在受支持的项目类型中时,这是由包自动完成的,所以这样做。
- 将 Nlua 命名空间添加到 MainPage 内容页面的代码隐藏顶部,如下所示:
using NLua;
- 为了方便以后使用,向 MainPage 类添加一个类级别的属性,如下所示:
Lua LuaState{get; set;}
- 现在,为简单起见,在页面构造函数中对其进行初始化:
LuaState = new Lua();
- 在页面的 xaml 中,添加一个用于输入文本的编辑字段和一个能够运行它的按钮:
<StackLayout>
<Editor
x:Name="edCode"
Placeholder="type your code here"
/>
<Button
x:Name="btnStartCode"
Text="compile"
HorizontalOptions="End"
VerticalOptions="EndAndExpand"
Clicked="btnStartCode_Clicked"
/>
</StackLayout>
- 在按钮单击处理程序中,添加代码以加载编辑框中的内容,然后让 nlua 执行它,如下所示:
async void btnStartCode_Clicked(object sender, EventArgs e)
{
try
{
LuaState.DoString(edCode.Text);
}
catch (Exception exc)
{
await DisplayAlert("error", $"A fatal error was incountered while running your code\nException details:\n\tException type: {exc.GetType().ToString()}\n\terror message from interpreter:{exc.Message}.", "OK");
}
}
- 现在,添加一个新类,随心所欲地调用它,我叫我的 tts。删除文件与生成的所有内容,然后在其中添加以下内容:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Essentials;
namespace autoaccess.scriptables
{
public class tts
{
public async void speak(params object[] messages)
{
foreach(var message in messages)
{
if (message == null)
{
await TextToSpeech.SpeakAsync("null value");
return;
}
await TextToSpeech.SpeakAsync(message.ToString());
}
}
}
}
- 回到主内容类,无论是在构造函数中还是在从构造函数调用的专用方法中,注册 lua 类型,如下所示:
LuaState["text_to_speech"=typeof(TextToSpeech);
预期行为
如果使用符号,它应该说出赋予函数的参数.
,例如 tts.speak("hello world")
实际行为
当执行带有.
符号的调用时,lua 解释器会抛出以下错误:
[string "chunk"]:1: 尝试调用一个 nil 值(字段 'speak')。
到目前为止我尝试了什么
- 首先,我尝试使用 typeof 关键字获取静态对象的类型,然后将其直接注册为 lua 可访问值,如上所示。如您所见,这引发了错误。
- 例如,如果我尝试像函数一样调用类型来获取文档中显示的新对象,它会再次失败。
- 如果我使用该
State.UseClrPackage();
方法,然后手动导入这些东西,它也不起作用,无法访问任何方法或变量,lua 说它们都是“空的”。
注意:经过仔细检查,我发现变量 lua sees 实际上是真正的 clr 类型,因为 lua 的 str 函数显示了完整的类型限定符,如 .net 中所示。但是,type 函数返回 userdata。
我没有让整个类型对 lua 可见,而是尝试使用名称创建一个 lua 表,然后添加键值对,其中键是方法名称,值是静态对象的方法,如返回通过 typeof(thing).GetMethod(MethodName) 强制转换为 LuaFunction 类型。这在一定程度上奏效了,尽管它很快对我来说太复杂和难以承受,所以我停止使用这种方法,因为我的代码库非常复杂。
我尝试的另一件事是为静态对象制作代理对象,其中实际上没有什么是静态的,即使这些方法返回 void 并作用于静态属性。
再一次,这有点工作,但是当静态方法的规范是 object.thing 时,我必须使用 object:thing。如果我尝试使用 object.thing 表示法,我会得到一个很长的错误,尽管我确信它的内容与手头的问题无关,所以不会在这里包含它。
结论
所以,正式地,我尽我所能,甚至在这里搜索,看看我是否能找到任何启发我的东西,但不幸的是没有运气。现在,你推荐我用什么?有什么我忽略的地方吗?