Управление. EndInvoke сбрасывает стек вызовов для исключения

Я не делаю большого программирования Windows GUI, таким образом, это может все быть общеизвестным людям, более знакомым с WinForms, чем я. К сожалению, я не смог найти, что любые ресурсы объясняют проблему, я встретился сегодня во время отладки.

Если мы называем EndInvoke на асинхронном делегате. Мы получим любое исключение, выданное во время осуществления повторно брошенного метода. Стек вызовов отразит первоисточник исключения.

Однако, если мы делаем что-то подобное в Windows. Формы. Управление, реализация Управления. EndInvoke сбрасывает стек вызовов. Это может наблюдаться простым тестом или путем рассмотрения кода в Отражателе. Выборка соответствующих норм от EndInvoke здесь:

if (entry.exception != null)
{
   throw entry.exception;
}

Я понимаю, что Begin/EndInvoke на Управлении и асинхронных делегатах отличаются, но я ожидал бы подобное поведение на Управлении. EndInvoke.

Есть ли какая-либо причина, Управление не делает то, что это - асинхронные делегаты, делают для сохранения стопки первоначального вызова?

7
задан Brian Rasmussen 12 April 2010 в 11:59
поделиться

4 ответа

Обратите также внимание, что Control.EndInvoke является одним из немногих управляемых EndInvokes в Framework (поэтому вы можете увидеть код в Reflector). Возможно, им следовало бы иметь неуправляемый помощник, который бросает с исходным стеком на месте.

На самом деле, я думаю, что это единственный управляемый EndInvoke, но есть и другие управляемые End* процедуры с параметром IAsyncResult. Я не проверял их все, но, похоже, все те, которые я просмотрел, просто бросают исключение или эффективно используют решение Стивена Клири о переходе к использованию GetWaiter.GetResult из .NET 4, в котором есть некоторые управляемые и неуправляемые махинации, чтобы попытаться восстановить стек для исключений.

1
ответ дан 8 December 2019 в 01:44
поделиться

Я не знаю настоящей причины, но могу предположить, что асинхронные делегаты сродни RPC, а управляющие делегаты могут основываться на отправке сообщений Win32. Различные технологии, поэтому влияние этой функции может быть разным. Асинхронный делегат получит выгоду от всего кода удаленного взаимодействия, для которого разработчик написал бы код для передачи стека вызовов исключений между разными процессами или компьютерами, в то время как делегаты управления будут имитировать RPC с PostMessage в рамках одного и того же процесса. Другая команда, другой код.

1
ответ дан 8 December 2019 в 01:44
поделиться

Я не прочитал 100% вашего сообщения, поэтому не уверен, помогает ли это, или я просто говорю очевидные вещи, {{1} } но когда исключение перехвачено и вы пишете

"throw iAmAnCaughtExceptionInstance;"

стек вызовов не будет сохранен, вы должны просто написать

"throw;"

, а затем стек вызовов будет сохранен

-3
ответ дан 8 December 2019 в 01:44
поделиться

Я не уверен, почему Control не делает этого (возможно, это просто недосмотр), но вы можете обойти это в .NET 4.0, запланировав Task для формы пользовательского интерфейса:

    private BackgroundWorker bgw;
    private TaskFactory uiTaskFactory;

    private void Form1_Load(object sender, EventArgs e)
    {
        this.uiTaskFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
        this.bgw = new BackgroundWorker();
        this.bgw.DoWork += bgw_DoWork;
        this.bgw.RunWorkerAsync();
    }

    void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        var task = this.uiTaskFactory.StartNew(this.OuterTaskFunction);
        try
        {
            task.Wait();
        }
        catch (Exception ex)
        {
            // Note: Full stack trace preserved
            MessageBox.Show(ex.InnerException.ToString());
        }
    }

    void OuterTaskFunction()
    {
        this.InnerTaskFunction();
    }

    void InnerTaskFunction()
    {
        throw new InvalidOperationException("Blah.");
    }
1
ответ дан 8 December 2019 в 01:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: