Как отловить исключение TargetInvocationException, созданное в.Net BackgroundWorker в Matlab?

Я пишу небольшое приложение в Matlab, используя GUIDE. Это приложение вызывает библиотеку.Net. Библиотека подключается к последовательному устройству. Используя 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, если бы я действительно должен был, я мог бы установить ловушку в моем static void Main() метод, чтобы я мог проверить внутреннее исключение.

try
{
    Application.Run(new Form1());
}
catch (TargetInvocationException exception)
{
    System.Windows.Forms.MessageBox.Show(exception.InnerException.ToString());
}

Я попробовал то же самое в Matlab, создав сценарий для запуска рисунка, но он все равно не уловил проблему. Кажется, как-то обойти подвох ниже. Matlab по-прежнему падает с тем же журналом событий, который я получаю, если просто дважды щелкнуть Figure1 запустить его.

try
    Figure1
catch ex
    warning(ex.message)
end

Итак, я действительно не знаю, куда идти отсюда. Я знаю, что это проблема XY. Мне действительно не нужно быть в состоянии поймать это исключение, но мне нужно уметь проверять внутреннее исключение, и я не делаю, что еще я могу сделать, чтобы взглянуть на него.


Я только что нашел этот интересный кусочек.

Обратные вызовы всех видов выполняются в контексте базовой рабочей области, а не в контексте подпрограммы, которая устанавливает функцию обратного вызова. Вы можете "ловить" только исключения операторов, которые вы вызываете напрямую, а не функции, автоматически выполняемые от вашего имени посредством обратного вызова.

Если это так, это объясняет, почему я не могу поймать исключение при создании фигуры из скрипта. Я облажался? Значит ли это, что я не могу поймать это исключение?

0 ответов

Другие вопросы по тегам