我正在使用 GUIDE 在 Matlab 中编写一个小型应用程序。此应用程序调用 .Net 库。该库连接到串行设备。使用 a BackgroundWorker
,库会轮询端口以获取新数据,并IncomingData
在收到新数据包时引发事件。(我知道这一点是因为我使用反编译器来查看库的内容。)
问题是我使用的 SDK 没有正确实现该RunWorkerCompleted
方法。e.Errors
在访问属性之前,它不会检查是否通过属性发生异常e.Result
。这会导致引发TargetInvocationException。此异常未处理并导致 Matlab 崩溃并在 Windows 事件日志中出现以下事件。内部异常没有序列化到事件日志中,所以我不知道究竟是什么导致了失败。
Application: MATLAB.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.Reflection.TargetInvocationException Stack: at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary() at System.ComponentModel.RunWorkerCompletedEventArgs.get_Result() at TargetInvocationIssueMVCE.BlackBox._backgroundWorker_RunWorkerCompleted(System.Object, System.ComponentModel.RunWorkerCompletedEventArgs) at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(System.ComponentModel.RunWorkerCompletedEventArgs) at System.ComponentModel.BackgroundWorker.AsyncOperationCompleted(System.Object) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object) at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
我能够通过以下 C# 类库复制我正在使用的库的行为。您可以将BlackBox
下面的示例视为我无法更改的库。
using System;
using System.ComponentModel;
namespace TargetInvocationIssueMVCE
{
public class BlackBox
{
private BackgroundWorker _backgroundWorker;
public event EventHandler<EventArgs> IncomingData;
public void Connect()
{
_backgroundWorker = new BackgroundWorker()
{
WorkerSupportsCancellation = true
};
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
_backgroundWorker.RunWorkerAsync();
}
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// BlackBox should check e.Errors first, but doesn't, so throws a TargetInvocationException that I can't seem to catch, so it crashes Matlab.
Console.Write(e.Result == null ? "Failure" : "Success");
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
throw new InvalidOperationException("I could be any exception.");
// the real worker is supposed to raise IncomingData here.
}
}
}
我在像这样的 Matlab GUIDE GUI 中调用这个库。
% --- Executes just before Figure1 is made visible.
function Figure1_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to Figure1 (see VARARGIN)
% load the library
NET.addAssembly('C:\path\to\TargetInvocationIssueMVCE.dll');
blackbox = TargetInvocationIssueMVCE.BlackBox();
handles.blackbox = blackbox;
addlistener(blackbox, 'IncomingData', @OnIncomingData);
% Choose default command line output for Figure1
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% ... some other irrelevant callbacks
% --- button click callback starts .Net BackgroundWorker process
function btnConnect_Callback(hObject, eventdata, handles)
try
handles.blackbox.Connect();
set(hObject, 'String', 'Disconnect');
catch ex
warning(ex.message);
set(hObject, 'Value', 1);
end
% --- Callback to process incoming data packets
function OnIncomingData(source, arg)
% It doesn't matter what I put here, the exception is raised before
% I ever get a packet event and Matlab crashes.
msgbox('Received Packet');
在.Net 中,如果我真的需要,我可以在我的方法中设置一个catch,static void Main()
这样我就可以检查内部异常。
try
{
Application.Run(new Form1());
}
catch (TargetInvocationException exception)
{
System.Windows.Forms.MessageBox.Show(exception.InnerException.ToString());
}
我在 Matlab 中通过创建一个脚本来运行该图进行了相同的尝试,但它仍然没有发现问题。它似乎以某种方式绕过了下面的问题。如果我只是双击Figure1
运行它,Matlab 仍然会因我得到的相同事件日志而崩溃。
try
Figure1
catch ex
warning(ex.message)
end
所以,我真的不知道从这里去哪里。我知道这是一个 XY 问题。我真的不需要能够捕捉到这个异常,但我确实需要能够检查内部异常,而且我不知道还能做些什么来查看它。
我刚刚发现了这个有趣的花絮。
各种回调在基本工作区的上下文中执行,而不是在设置回调函数的例程的上下文中。您只能“捕获”您直接调用的语句的异常,而不是通过回调自动执行的函数的异常。
如果这是真的,它将解释为什么我在从脚本创建图形时无法捕获异常。我搞砸了吗?这是否意味着我无法捕捉到这个异常?