使用MoonSharp在Lua中遍历C#字典遇类型转换异常求助
我之前也踩过MoonSharp类型转换的类似坑,你遇到的ScriptRuntimeException: bad argument #1 to 'next' (table expected, got userdata)错误,主要是因为MoonSharp的自动类型转换没有正确识别你的IDictionary实例,下面是几个常见的原因和对应的解决办法:
1. 未注册CLR集合类型的转换支持
MoonSharp默认不会自动处理所有CLR集合类型的转换,你需要手动注册Dictionary或IDictionary的类型转换器,或者直接启用标准集合的转换支持。
在初始化Lua环境的时候,添加这段代码:
// 一次性启用当前程序集中所有CLR类型的UserData支持(包括集合) UserData.RegisterAssembly(); // 或者精准注册你用到的字典类型 UserData.RegisterType(typeof(Dictionary<int, Entity>)); UserData.RegisterType(typeof(IDictionary<int, Entity>));
注册之后,MoonSharp就会知道如何把你的Entities字典转换成Lua可识别的表结构了。
2. 只读接口类型导致转换失效
MoonSharp对接口类型的自动转换支持不如具体类稳定,虽然你的Entities实际实例是Dictionary<int, Entity>,但声明为IDictionary<int, Entity>可能会让MoonSharp无法正确识别它的集合特性。
你可以尝试把字段声明改成具体的实现类:
public readonly Dictionary<int, Entity> Entities = new Dictionary<int, Entity>();
之后再重新注册类型,Lua环境就能正确解析并转换这个字典了。
3. 检查World对象的暴露方式
如果World是通过UserData暴露给Lua的,要确保Entities字段是公共可访问的,并且MoonSharp能正确解析它的类型。你可以先在Lua里打印type(World.Entities),如果输出是userdata,说明转换确实没生效,这时候就需要回到前面的类型注册步骤排查。
另外,确认你是通过正确的方式把World实例传给Lua的,比如:
script.Globals["World"] = yourWorldInstance;
4. 手动转换为MoonSharp Table(兜底方案)
如果上面的方法都不奏效,你可以手动把字典转换成MoonSharp的Table对象,再暴露给Lua:
var luaTable = new Table(yourLuaScriptInstance); foreach (var kvp in yourWorldInstance.Entities) { luaTable[kvp.Key] = kvp.Value; } yourLuaScriptInstance.Globals["Entities"] = luaTable;
之后在Lua里直接用for k,v in pairs(Entities) do -- something end就能正常遍历了。
内容的提问来源于stack exchange,提问作者Bab




