Обработка исключений с несколькими формами

Вот (немного) более простая версия:

CREATE PROCEDURE dbo.CalculateAge 
    @dayOfBirth datetime
AS

DECLARE @today datetime, @thisYearBirthDay datetime
DECLARE @years int, @months int, @days int

SELECT @today = GETDATE()

SELECT @thisYearBirthDay = DATEADD(year, DATEDIFF(year, @dayOfBirth, @today), @dayOfBirth)

SELECT @years = DATEDIFF(year, @dayOfBirth, @today) - (CASE WHEN @thisYearBirthDay > @today THEN 1 ELSE 0 END)

SELECT @months = MONTH(@today - @thisYearBirthDay) - 1

SELECT @days = DAY(@today - @thisYearBirthDay) - 1

SELECT @years, @months, @days
GO
10
задан 21 November 2009 в 16:07
поделиться

2 ответа

У меня такое же поведение, как и у вас. Я не знаю, почему это происходит, но кажется плохой идеей предполагать, что исключение, созданное из события в форме, появится в стеке вызова ShowDialog (). Было бы лучше сделать эти две вещи:

  • Перехватывать и обрабатывать исключения в обработчиках событий в Form2 там, где это имеет смысл, и когда вы можете сделать что-то значимое с исключением.
  • Добавьте обработчик необработанных исключений (ʻApplication_ThreadException`) для всего приложения, чтобы перехватить любые необработанные исключения.

Обновление: вот трассировки стека. Версия отладки:

System.DivideByZeroException: Attempted to divide by zero.
   at WindowsFormsApplication1.Form2.button1_Click(Object sender, EventArgs e) in ...\WindowsFormsApplication1\Form2.cs:line 27
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.RunDialog(Form form)
   at System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
   at System.Windows.Forms.Form.ShowDialog()
   at WindowsFormsApplication1.Form1.button1_Click(Object sender, EventArgs e) in ...\WindowsFormsApplication1\Form1.cs:line 45

Выпуск:

System.DivideByZeroException: Attempted to divide by zero.
   at WindowsFormsApplication1.Form2.button1_Click(Object sender, EventArgs e) in ...\WindowsFormsApplication1\Form2.cs:line 27
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Обратите внимание, что System.Windows.Forms.Form.ShowDialog () не находится в трассировке стека в режиме выпуска, поэтому ваша попробуйте {} catch {} ничего не делает. Также примечательно то, что в случае отладки он использует NativeWindow.DebuggableCallback , который предположительно предназначен для помощи при отладке, не нарушая работу стека, тогда как в режиме выпуска используется NativeWindow.Callback .

4
ответ дан 3 December 2019 в 22:37
поделиться

Да, это сделано намеренно и тесно связано с принципом работы Windows Forms. В приложении Winforms код запускается в ответ на сообщения, отправленные в активное окно Windows. Каждое собственное приложение Windows содержит цикл сообщений для обнаружения этих сообщений. Сантехника Winforms гарантирует, что один из ваших обработчиков событий будет запускаться в ответ; button1_Click в вашем примере кода.

Большинство элементов управления Winforms реализуют свои собственные обработчики событий. Например, PictureBox имеет обработчик событий Paint, который обеспечивает отрисовку его изображения на экране. Все это делается автоматически, вам не нужно писать код самостоятельно, чтобы это работало.

Однако существует проблема, когда этот код генерирует исключение, у вас нет способа поймать такое исключение, поскольку ни один из ваш собственный код был задействован. Другими словами, вам некуда вводить собственный блок попытки. Самая последняя часть кода вашей собственной программы, которая была задействована, - это код, запускающий цикл сообщений. Вызов метода Application.Run (), обычно в Program.cs. Или вызов Form.ShowDialog (), если вы открываете диалог. Любой из этих методов запускает цикл сообщений. Помещение блока try вокруг вызова Application.Run () бесполезно, приложение завершает работу после перехвата исключения.

Для решения этой проблемы код цикла сообщений Winforms содержит блок try вокруг кода, который отправляет событие . Его предложение catch отображает диалоговое окно, о котором вы упомянули, оно реализуется классом ThreadExceptionDialog.

Переходим к сути вашего вопроса: это предложение catch действительно мешает устранению проблем с вашим кодом при отладке. Отладчик остановится только при возникновении исключения, если нет блока catch, обрабатывающего исключение. Но когда ваш код генерирует исключение, вы захотите узнать об этом при отладке. Ранее упомянутый код в цикле сообщений знает, подключен ли отладчик. Если это так, он отправляет события без блока try / catch. Теперь, когда ваш код генерирует исключение, нет предложения catch для его обработки, и отладчик остановит программу, давая вам шанс выяснить, что пошло не так.

Возможно, теперь вы понимаете, почему ваша программа ведет себя именно так. делает. При отладке предложение catch в цикле сообщений отключено, что дает предложению catch в коде Form1 возможность поймать исключение. Когда вы этого не сделаете, предложение catch цикла сообщений обрабатывает исключение (путем отображения диалогового окна) и предотвращает передачу исключения в код Form1.

Вы можете вообще предотвратить использование предложения catch цикла сообщений, вызвав метод Application.SetUnhandledExceptionMode () , передавая UnhandledExceptionMode.ThrowException. Сделайте это в методе Main () перед вызовом Application.Run (). Теперь ваша программа будет вести себя одинаково в любом случае.

В общем, это неплохая идея, предоставление пользователю возможности продолжить в диалоговом окне исключения является сомнительной функцией. Реализуйте обработчик событий для события AppDomain.UnhandledException в этом случае, чтобы у пользователя была хоть какая-то диагностика.

SetUnhandledExceptionMode (), передавая UnhandledExceptionMode.ThrowException. Сделайте это в методе Main () перед вызовом Application.Run (). Теперь ваша программа будет вести себя одинаково в любом случае.

В общем, это неплохая идея, предоставление пользователю возможности продолжить в диалоговом окне исключения является сомнительной функцией. Реализуйте обработчик событий для события AppDomain.UnhandledException в этом случае, чтобы у пользователя была хоть какая-то диагностика.

SetUnhandledExceptionMode (), передавая UnhandledExceptionMode.ThrowException. Сделайте это в методе Main () перед вызовом Application.Run (). Теперь ваша программа будет вести себя одинаково в любом случае.

В общем, это неплохая идея, предоставление пользователю возможности продолжить в диалоговом окне исключения является сомнительной функцией. Реализуйте обработчик событий для события AppDomain.UnhandledException в этом случае, чтобы у пользователя была хоть какая-то диагностика.

11
ответ дан 3 December 2019 в 22:37
поделиться
Другие вопросы по тегам:

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