如何捕获Matlab中.Net BackgroundWorker引发的TargetInvocationException?

时间:2016-05-24 18:45:52

标签: .net matlab exception-handling matlab-guide targetinvocationexception

我正在使用GUIDE在Matlab中编写一个小应用程序。 此应用程序调用.Net库。 该库连接到串行设备。 使用BackgroundWorker,库会轮询端口以获取新数据,并在收到新数据包时引发IncomingData事件。 (我知道这是因为我使用反编译器来查看库的内容。)

问题是我使用的SDK没有implement the RunWorkerCompleted method properly。在访问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指南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中,如果我真的不得不这样做,我可以在我的static void Main()方法中设置一个catch,以便我可以检查内部异常。

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问题。我不真的需要能够捕获此异常,但我 需要能够检查内部异常我不喜欢我还能做些什么来看看它。

我刚发现这个interesting tidbit

  

各种回调都是在基础环境中执行的   工作空间,而不是在设置回调的例程的上下文中   功能。您只能“捕获”您调用的语句的例外情况   直接,而不是代表您自动执行的功能   通过回调。

如果这是真的,它将解释为什么在从脚本创建图形时我无法捕获异常。我搞砸了吗?这是否意味着我无法捕获此异常?

0 个答案:

没有答案