如何从 Lua 中调用可以抛出异常的 C# 委托

在基于 Linux 的 Docker 镜像中运行以下代码会导致 CLR 崩溃。

static void Main(string[] args)
    {
        System.Console.WriteLine("程序开始");
        using (NLua.Lua luaState = new NLua.Lua())
        {
            System.Action invoke = () => throw new System.Exception("异常信息");
            luaState["invoke"] = invoke;
            try
            {
                System.Console.WriteLine("执行委托");
                luaState.DoString(@"invoke()");
            }
            catch (System.Exception ex)
            {
                // 不会执行到这里
                System.Console.WriteLine("捕获到异常");
                throw;
            }
        }

    }

我做错了什么吗?

Dockerfile 是 Visual Studio 提供的默认建议,并且是从 Visual Studio 启动的进程。

在 Docker 外部运行程序,即在 Windows 主机上运行,结果是符合预期的。(执行到 catch 语句并且不会导致 CLR 出现致命错误。)

将委托包装在“pcall”中不能解决该问题。

可以通过注册函数而不是发送委托来避免该问题。 如果委托不抛出异常,则按预期调用它。

镜像的控制台日志如下:

程序开始
执行委托
Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.Exception: 异常信息
at LuaTest.Program.<>c.<Main>b__0_0() in C:\Source\Tests\LuaTest\Program.cs:line 10
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at NLua.MetaFunctions.CallDelegateInternal(Lua luaState)
at NLua.MetaFunctions.CallDelegate(IntPtr state)
at KeraLua.NativeMethods.lua_pcallk(IntPtr luaState, Int32 nargs, Int32 nresults, Int32 errorfunc, IntPtr ctx, IntPtr k)
at KeraLua.Lua.PCall(Int32 arguments, Int32 results, Int32 errorFunctionIndex)
at NLua.Lua.DoString(String chunk, String chunkName)
at LuaTest.Program.Main(String[] args) in C:\Source\Tests\LuaTest\Program.cs:line 15
Fatal error. Internal CLR error. (0x80131506)
at KeraLua.NativeMethods.lua_pcallk(IntPtr, Int32, Int32, Int32, IntPtr, IntPtr)
at KeraLua.NativeMethods.lua_pcallk(IntPtr, Int32, Int32, Int32, IntPtr, IntPtr)
at KeraLua.Lua.PCall(Int32, Int32, Int32)
at NLua.Lua.DoString(System.String, System.String)
at LuaTest.Program.Main(System.String[])

原文链接 https://stackoverflow.com/questions/69013446

点赞
stackoverflow用户1986513
stackoverflow用户1986513

这似乎是 NLua 中 MetaFunctions.CallDelegate 的一个 bug。委托的调用没有在 try-catch 块中。与LuaMethodWrapper.Call相比。

致命错误可能是由于尝试通过调用 longjmp 的非托管代码来传播异常所致。请参见 dotnet core 关于异常互操作性的笔记。

最直接的解决方法是使用 register function 注册委托:

Action action=()=>throw new Exception()
luastate.RegisterFunction("invoke",action.Target,action.Method);
2021-09-02 14:34:04