Почему исключение .NET не перехватывается блоком try / catch?

Я работаю над проектом с использованием библиотеки парсера ANTLR для C#. Я построил грамматику для анализа текста, и она хорошо работает. Однако, когда синтаксический анализатор сталкивается с недопустимым или неожиданным токеном, он выдает одно из многих исключений. Проблема заключается в том, что в некоторых случаях (не во всех) мой блок try / catch не перехватывает его и вместо этого останавливает выполнение как необработанное исключение.

Проблема для меня в том, что я не могу воспроизвести эту проблему где-либо еще, кроме как в моем полном коде. Стек вызовов показывает, что исключение определенно возникает в моем блоке try / catch (Exception). Единственное, о чем я могу думать, это то, что между моим кодом и кодом, генерирующим исключение, происходит несколько вызовов сборки ANTLR, и в этой библиотеке не включена отладка, поэтому я не могу пройти через нее. Интересно, запрещают ли не отлаживаемые сборки пузыри исключений? Стек вызовов выглядит так: вызовы внешней сборки находятся в Antlr.Runtime:

    Expl.Itinerary.dll!TimeDefLexer.mTokens() Line 1213 C#
    Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken() + 0xfc bytes 
    Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer() + 0x22c bytes   
    Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.LT(int k = 1) + 0x68 bytes
    Expl.Itinerary.dll!TimeDefParser.prog() Line 109 + 0x17 bytes   C#
    Expl.Itinerary.dll!Expl.Itinerary.TDLParser.Parse(string Text = "", Expl.Itinerary.IItinerary Itinerary = {Expl.Itinerary.MemoryItinerary}) Line 17 + 0xa bytes C#

Фрагмент кода из самого нижнего вызова в Parse () выглядит так:

     try {
        // Execution stopped at parser.prog()
        TimeDefParser.prog_return prog_ret = parser.prog();
        return prog_ret == null ? null : prog_ret.value;
     }
     catch (Exception ex) {
        throw new ParserException(ex.Message, ex);
     }

На мой взгляд, предложение catch (Exception) должно было фиксировать любое исключение. Есть ли причина, по которой это не так?

Обновлять: Я проследил внешнюю сборку с помощью Reflector и не нашел никаких доказательств наличия каких-либо потоков. Сборка кажется просто служебным классом времени выполнения для кода, сгенерированного ANTLR. Исключение создается методом TimeDefLexer.mTokens (), его тип - NoViableAltException, который является производным от RecognitionException -> Exception. Это исключение возникает, когда лексер не может понять следующий токен в потоке; другими словами, неверный ввод. Это исключение должно произойти, но оно должно было быть обнаружено моим блоком try / catch.

Кроме того, повторное генерирование ParserException действительно не имеет отношения к этой ситуации. Это уровень абстракции, который принимает любое исключение во время синтаксического анализа и преобразует его в мое собственное исключение ParserException. Проблема с обработкой исключений, с которой я столкнулся, никогда не достигает этой строки кода. Фактически, я закомментировал часть «выбросить новое исключение ParserException» и по-прежнему получил тот же результат.

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

Кто-то однажды предположил, что иногда VS слишком активен при перехвате обработанных исключений в режиме отладки, но эта проблема также возникает в режиме выпуска.

Чувак, я все еще в тупике! Я не упоминал об этом раньше, но я использую VS 2008, и весь мой код - 3.5. Внешняя сборка - 2.0. Кроме того, некоторые из моих кодов являются подклассами класса сборки 2.0. Может ли несовпадение версий вызвать эту проблему?

Обновление 2: Мне удалось устранить конфликт версий .NET, перенеся соответствующие части моего кода .NET 3.5 в проект .NET 2.0 и воспроизведя тот же сценарий. Мне удалось воспроизвести одно и то же необработанное исключение при последовательной работе в .NET 2.0.

Я узнал, что ANTLR недавно выпустил 3.1. Итак, я обновился с 3.0.1 и повторил попытку. Оказывается, сгенерированный код немного переработан, но в моих тестовых примерах возникает то же необработанное исключение.

Обновление 3: Я воспроизвел этот сценарий в упрощенный проект VS 2008. Не стесняйтесь скачивать и проверять проект на себе. Я применил все замечательные предложения, но пока не смог преодолеть это препятствие.

Если вы можете найти обходной путь, поделитесь своими выводами. Еще раз спасибо!


Спасибо, но VS 2008 автоматически прерывается при необработанных исключениях. Кроме того, у меня нет диалогового окна «Отладка-> Исключения». Вызываемое исключение NoViableAltException полностью предназначено и предназначено для перехвата пользовательским кодом. Поскольку он не перехватывается должным образом, выполнение программы неожиданно останавливается как необработанное исключение.

Выброшенное исключение является производным от Exception, и многопоточность с ANTLR не выполняется.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
47
0
63 020
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

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

Независимо от того, была ли сборка скомпилирована как сборка выпуска, исключение обязательно должно «всплывать» до вызывающего, нет причин, по которым сборка, не компилируемая в режиме отладки, должна иметь какое-либо влияние на это.

Я согласен с тем, что Даниэль предполагает, что, возможно, исключение происходит в отдельном потоке - попробуйте подключить событие исключения потока в Application.ThreadException. Это должно быть вызвано при возникновении любого необработанного исключения потока. Вы можете адаптировать свой код таким образом: -

using System.Threading;

...

void Application_ThreadException(object sender, ThreadExceptionEventArgs e) {
  throw new ParserException(e.Exception.Message, e.Exception);
}    

 ...

 var exceptionHandler = 
    new ThreadExceptionEventHandler(Application_ThreadException);
 Application.ThreadException += exceptionHandler;
 try {
    // Execution stopped at parser.prog()
    TimeDefParser.prog_return prog_ret = parser.prog();
    return prog_ret == null ? null : prog_ret.value;
 }
 catch (Exception ex) {
    throw new ParserException(ex.Message, ex);
 }
 finally {
    Application.ThreadException -= exceptionHandler;
 }

Вы можете настроить VS.Net на прерывание, как только произойдет какое-либо исключение. Просто запустите свой проект в режиме отладки, и он остановится, как только возникнет исключение. Тогда вы должны лучше понять, почему его не поймали.

Также вы можете вставить код в поймать все необработанные исключения. Прочтите ссылку для получения дополнительной информации, но основы - это эти две строки.

Application.ThreadException += new ThreadExceptionEventHandler(ThreadExceptionHandler);

 // Catch all unhandled exceptions in all threads.
 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler);

Да, и в отношении того, что сказал Кибби; если вы выберете «Отладка | Исключения в VS» и просто щелкните все поля в столбце «Выброшенный», он должен выбрать все вверх AFAIK как «исключение первого шанса», т.е. VS укажет, когда исключение о будет обработано всем остальным и перерыв на соответствующий код. Это должно помочь с отладкой.

"Also, you can put some code in to catch all unhandled exceptions. Read the link for more info, but the basics are these two lines."

Это неправда. Это использовалось для перехвата всех необработанных исключений в .NET 1.0 / 1.1, но это была ошибка, и не предполагалось, и она была исправлена ​​в .NET 2.0.

AppDomain.CurrentDomain.UnhandledException 

Предназначен только для использования в качестве последней возможности журнала, чтобы вы могли зарегистрировать исключение до выхода из программы. Он не будет перехватывать исключение, начиная с версии 2.0 (хотя в .NET 2.0, по крайней мере, есть значение конфигурации, которое вы можете изменить, чтобы оно работало как 1.1, но это не рекомендуется использовать).

Стоит отметить, что есть несколько исключений, которые вы перехватываете с помощью не можешь, например StackOverflowException и OutOfMemoryException. В противном случае, как предполагали другие люди, это может быть исключение в каком-то фоновом потоке. Также я почти уверен, что вы также не можете поймать некоторые / все неуправляемые / собственные исключения.

Вы используете .Net 1.0 или 1.1? Если это так, то catch (Exception ex) не будет перехватывать исключения из неуправляемого кода. Вместо этого вам нужно будет использовать catch {}. См. Эту статью для получения дополнительной информации:

http://www.netfxharmonics.com/2005/10/net-20-trycatch-and-trycatchexception/

Было бы здорово, если бы вы резюмировали ссылку, потому что статьи больше нет по этому адресу.

pqsk 06.08.2014 19:11

Я не понимаю ... ваш блок catch просто генерирует новое исключение (с тем же сообщением). Это означает, что ваше заявление:

The problem is that in some cases (not all) that my try/catch block won't catch it and instead stops execution as an unhandled exception.

это именно то, что должно произойти ожидал.

Я согласен с Даниэль Аугер и крон, что это пахнет исключением, которое имеет какое-то отношение к потокам. Помимо этого, вот мои другие вопросы:

  1. Что говорится в полном сообщении об ошибке? Что это за исключение?
  2. Основываясь на трассировке стека, которую вы здесь предоставили, не является ли исключение, созданное вашим кодом в TimeDefLexer.mTokens ()?

Наилучший вариант звучит как настройка Visual Studio для прерывания всех необработанных исключений (диалоговое окно «Отладка -> Исключения», установите флажок «Исключения среды CLR» и, возможно, другие). Затем запустите вашу программу в режиме отладки. Когда код парсера ANTLR выдает исключение, оно должно быть перехвачено Visual Studio и позволит вам увидеть, где оно происходит, тип исключения и т. д.

Судя по описанию, блок catch кажется правильным, поэтому может произойти одно из нескольких:

  1. синтаксический анализатор на самом деле не генерирует исключение
  2. синтаксический анализатор в конечном итоге выбрасывает что-то, что не является производным от System.Exception
  3. возникает исключение в другом потоке, который не обрабатывается

Похоже, вы исключили проблему №3.

I traced through the external assembly with Reflector and found no evidence of threading whatsoever.

Вы не можете найти потоковую передачу, это не означает, что ее нет.

.NET имеет «пул потоков», который представляет собой набор «запасных» потоков, которые в основном простаивают. Некоторые методы заставляют вещи работать в одном из потоков пула потоков, поэтому они не блокируют ваше основное приложение.

Наглядными примерами являются такие вещи, как ThreadPool.QueueUserWorkItem, но есть много-много других вещей, которые также могут запускать в пуле потоков вещи, которые не выглядят столь очевидными, например Delegate.BeginInvoke

Действительно, нужно делай то, что предлагает кибби.

To me, a catch (Exception) clause should've captured any exception whatsoever. Is there any reason why it wouldn't?

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

my try/catch block won't catch it and instead stops execution as an unhandled exception.

Вам нужно найти, что вызывает процесс выхода. Это может быть что-то иное, чем необработанное исключение. Вы можете попробовать использовать собственный отладчик с точкой останова, установленной на "{,, kernel32.dll} ExitProcess". Затем используйте SOS, чтобы определить, какой управляемый код вызывает процесс выхода.

Я не уверен, что я не понимаю, но если да, то я вижу, что отладчик останавливает выполнение с «необработанным исключением» типа NoViableAltException. Изначально я ничего не знал об этом пункте меню Debug-> Exceptions, потому что MS ожидает, что вы во время установки VS зафиксируете профиль, когда вы не знаете, чем они отличаются. Судя по всему, Я не был в профиле разработчика C#, и мне не хватало этой опции. После окончательной отладки всех выброшенных исключений CLR я, к сожалению, не смог обнаружить какое-либо новое поведение, приводящее к причине этой проблемы необработанного исключения. Все вызванные исключения ожидались и предположительно обрабатывались в блоке try / catch.

Я пересмотрел внешнюю сборку и признаков многопоточности нет. Под этим я подразумеваю, что ссылки на System.Threading не существует и делегаты вообще не использовались. Я знаком с тем, что представляет собой создание экземпляра потока. Я проверяю это, наблюдая за набором инструментов Threads во время необработанного исключения, чтобы увидеть, что есть только один запущенный поток.

У меня есть нерешенная проблема с ребятами из ANTLR, так что, возможно, они уже могли решить эту проблему раньше. Мне удалось воспроизвести его в проекте простого консольного приложения с использованием .NET 2.0 и 3.5 под VS 2008 и VS 2005.

Это просто проблема, потому что это заставляет мой код работать только с известными действительными входными данными парсера. Использование метода IsValid() было бы рискованным, если бы он вызвал необработанное исключение на основе ввода данных пользователем. Я буду держать этот вопрос в актуальном состоянии, когда об этой проблеме станет больше.

@spoulson,

Если вы можете воспроизвести это, вы можете опубликовать его где-нибудь? Один из способов, который вы можете попробовать, - это использовать WinDBG с расширениями SOS для запуска приложения и перехвата необработанного исключения. Он прервется при первом исключении (до того, как среда выполнения попытается найти обработчик), и в этот момент вы сможете увидеть, откуда оно исходит и из какого потока.

Если вы раньше не использовали WinDBG, это может показаться немного утомительным, но вот хороший урок:

http://blogs.msdn.com/johan/archive/2007/11/13/getting-started-with-windbg-part-i.aspx

После запуска WinDBG вы можете переключить прерывание необработанных исключений, перейдя в Debug-> Event Filters.

Вы пытались распечатать (Console.WriteLine ()) исключение внутри предложения catch, а не использовать визуальную студию и запускать приложение на консоли?

Лично я вообще не убежден в теории потоков.

Один раз я видел это раньше, когда я работал с библиотекой, которая также определяла Exception, и то использование, которое я имел в виду, означает, что фактический Catch относится к другому типу «Exception» (если он был полностью определен, это был Company. Lib.Exception, но это было не из-за использования), поэтому, когда дело дошло до перехвата обычного исключения, которое было выброшено (какое-то исключение аргумента, если я правильно помню), он просто не мог его поймать, потому что тип не совпадал.

Итак, есть ли другой тип исключения в другом пространстве имен, который используется в этом классе?

Обновлено: Быстрый способ проверить это - убедиться, что в вашем предложении catch вы полностью квалифицировали тип исключения как «System.Exception» и дали ему вихрь!

EDIT2: ОК, я пробовал код и пока признаю поражение. Мне придется еще раз взглянуть на это утром, если никто не придумал решения.

Я с @Shaun Austin - попробуйте обернуть попытку полным именем

catch (System.Exception)

и посмотрите, помогает ли это. В документе ANTLR сказано, какие исключения следует выдавать?

Хм, я не понимаю в чем проблема. Я скачал и попробовал ваш пример файла решения.

Исключение создается в TimeDefLexer.cs, строка 852, которое впоследствии обрабатывается блоком catch в Program.cs, который просто сообщает Обработанное исключение.

Если я раскомментирую блок catch над ним, вместо этого он войдет в этот блок.

В чем, кажется, проблема?

Как сказал Кибби, Visual Studio остановится на исключениях, но если вы попросите ее продолжить, исключение будет перехвачено вашим кодом.

Я загрузил образец проекта VS2008 и здесь тоже немного озадачен. Однако мне удалось обойти исключения, хотя, вероятно, не так, как вам подходит. Но вот что я обнаружил:

В этом сообщение списка рассылки обсуждалась, похоже, та же проблема, с которой вы столкнулись.

Оттуда я добавил пару фиктивных классов в основной файл program.cs:

class MyNoViableAltException : Exception
{
    public MyNoViableAltException()
    {
    }
    public MyNoViableAltException(string grammarDecisionDescription, int decisionNumber, int stateNumber, Antlr.Runtime.IIntStream input)
    {
    }
}
class MyEarlyExitException : Exception
{
    public MyEarlyExitException()
    {
    }

    public MyEarlyExitException(int decisionNumber, Antlr.Runtime.IIntStream input)
    {
    }
}

а затем добавил строки using в TimeDefParser.cs и TimeDefLexer.cs:

using NoViableAltException = MyNoViableAltException;
using EarlyExitException = NoViableAltException; 

При этом исключения будут перемещаться в поддельные классы исключений и могут обрабатываться там, но исключение по-прежнему генерируется в методе mTokens в TimeDefLexer.cs. Обертывание этого в try catch в этом классе вызвало исключение:

            try
            {
                alt4 = dfa4.Predict(input);
            }
            catch
            {
            }

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

Ничего себе, из отчетов на данный момент 2 работали правильно, а в 1 возникла проблема, о которой я сообщил. Какие версии Windows, Visual Studio используются и .NET framework с номерами сборок?

Я использую XP SP2, VS 2008 Team Suite (9.0.30729.1 SP), C# 2008 (91899-270-92311015-60837) и .NET 3.5 SP1.

Ответ принят как подходящий

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

В третьем случае из вашего воспроизведения, я полагаю, вы получаете следующее сообщение: «NoViableAltException не было обработано кодом пользователя» и стек вызовов, который выглядит следующим образом:

         [External Code]    
    >   TestAntlr-3.1.exe!TimeDefLexer.mTokens() Line 852 + 0xe bytes   C#
        [External Code] 
        TestAntlr-3.1.exe!TimeDefParser.prog() Line 141 + 0x14 bytes    C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.ParseTest(string Text = "foobar;") Line 49 + 0x9 bytes C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.Main(string[] args = {string[0x00000000]}) Line 30 + 0xb bytes C#
        [External Code] 

Если вы щелкните правой кнопкой мыши в окне стека вызовов и запустите команду «Включить показ внешнего кода», вы увидите следующее:

        Antlr3.Runtime.dll!Antlr.Runtime.DFA.NoViableAlt(int s = 0x00000000, Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream}) + 0x80 bytes   
        Antlr3.Runtime.dll!Antlr.Runtime.DFA.Predict(Antlr.Runtime.IIntStream input = {Antlr.Runtime.ANTLRStringStream}) + 0x21e bytes  
    >   TestAntlr-3.1.exe!TimeDefLexer.mTokens() Line 852 + 0xe bytes   C#
        Antlr3.Runtime.dll!Antlr.Runtime.Lexer.NextToken() + 0xc4 bytes 
        Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.FillBuffer() + 0x147 bytes   
        Antlr3.Runtime.dll!Antlr.Runtime.CommonTokenStream.LT(int k = 0x00000001) + 0x2d bytes  
        TestAntlr-3.1.exe!TimeDefParser.prog() Line 141 + 0x14 bytes    C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.ParseTest(string Text = "foobar;") Line 49 + 0x9 bytes C#
        TestAntlr-3.1.exe!TestAntlr_3._1.Program.Main(string[] args = {string[0x00000000]}) Line 30 + 0xb bytes C#
        [Native to Managed Transition]  
        [Managed to Native Transition]  
        mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x39 bytes    
        Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2b bytes  
        mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x3b bytes   
        mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x81 bytes    
        mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x40 bytes

Сообщение отладчика сообщает вам, что исключение, возникшее за пределами вашего кода (из NoViableAlt), проходит через код, которым вы владеете, в TestAntlr-3.1.exe! TimeDefLexer.mTokens () без обработки.

Формулировка сбивает с толку, но это не означает, что исключение не обнаружено. Отладчик сообщает вам, что код, которым вы владеете, mTokens () "должен быть устойчивым к этому исключению, передаваемому через него.

С чем можно поиграть, чтобы увидеть, как это выглядит для тех, кто не воспроизводил проблему:

  • Перейдите в Инструменты / Параметры / Отладка и выключить "Включить только мой код" (Только управляемый) ". Или вариант.
  • Перейдите в Отладчик / Исключения и отключите "Необработанный пользователем" для Исключения общеязыковой среды выполнения.

У меня была очень похожая проблема - также с лексером ANTLR, который я построил для Silverlight ... Отключение «Включить только мой код» в отладчике решило проблему. Кажется, что отладчик вмешался до моего оператора catch, и если вы не знали, что происходило, это выглядело так, как будто приложение останавливается, не перехватив ваше исключение. Я не совсем понимаю, почему отладчик делает это или как он отличает «мой код» от «моих библиотек» и т. д., Но это было исправление. (Кстати, я не вижу опцию "необработанный пользователем" в VS 2010.

Pat Niemeyer 06.10.2010 22:57

Как только вы отключите «Включить только мой код», параметры «Необработанный пользователем» исчезнут из Отладчика / Исключений. Единственный вариант - поставить галочку «Брошено».

spoulson 21.07.2011 04:01

Я скачал ваш код, и все работает как положено.

Отладчик Visual Studio правильно перехватывает все исключения. Блоки захвата работают должным образом.

Я использую Windows 2003 server SP2, VS2008 Team Suite (9.0.30729.1 SP)

Я пытался скомпилировать ваш проект для .NET 2.0, 3.0 и 3.5

@Steve Steiner, параметры отладчика, о которых вы упомянули, не имеют ничего общего с этим поведением.

Я попытался поиграть с этими параметрами без видимых эффектов - блоки catch смогли перехватить все исключения.

Я считаю, что Стив Штайнер прав. Изучая предложения Стива, я наткнулся на эта ветка, говорящий о опции «Включить только мой код» в Инструменты | Параметры | Отладчик | Общие. Предполагается, что отладчик сломается в определенных условиях, когда непользовательский код либо генерирует, либо обрабатывает исключение. Я не совсем уверен, почему это вообще имеет значение или почему отладчик конкретно говорит, что исключение не было обработано, когда это было на самом деле.

Мне удалось устранить ложные перерывы, отключив параметр «Включить только мой код». Это также изменяет диалоговое окно «Отладка | Исключения», удаляя столбец «Обработано пользователем», поскольку он больше не применяется. Или вы можете просто снять флажок «Обрабатывается пользователем» для CLR и получить тот же результат.

Большое спасибо за помощь!

Стив Штайнер прав в том, что исключение происходит из библиотеки antlr, проходит через метод mTokens () и попадает в библиотеку antlr. Проблема в том, что этот метод автоматически генерируется antlr. Следовательно, любые изменения для обработки исключения в mTokens () будут перезаписаны, когда вы сгенерируете свои классы парсера / лексера.

По умолчанию antlr регистрирует ошибки и пытается восстановить синтаксический анализ. Вы можете переопределить это так, чтобы parser.prog () генерировал исключение при обнаружении ошибки. Из вашего примера кода я думаю, что это именно то поведение, которого вы ожидали.

Добавьте этот код в свой граммерный (.g) файл. Вам также необходимо отключить «Включить только мой код» в меню отладки.

@members {

    public override Object RecoverFromMismatchedSet(IIntStream input,RecognitionException e,    BitSet follow)  
    {
        throw e;
    }
}

@rulecatch {
    catch (RecognitionException e) 
    {
        throw e;
    }
}

Это моя попытка создать версию C# примера, приведенного в главе «Выход из распознавателя при первой ошибке» книги «Окончательный справочник по ANTLR».

Надеюсь, это то, что вы искали.

Я могу рассказать вам, что здесь происходит ...

Visual Studio ломается, потому что считает, что исключение не обработано. Что значит необработанный? Ну, в Visual Studio есть настройка в Инструменты ... Параметры ... Отладка ... Общие ... «Включить только мой код (только управляемый)». Если это отмечено, и если исключение распространяется из вашего кода и во фрейм стека, связанный с вызовом метода, который существует в сборке, которая является «НЕ ВАШИМ КОДОМ» (например, Antlr), это считается «необработанным». По этой причине я отключаю эту функцию «Включить только мой код». Но, если вы спросите меня, это отстой ... допустим, вы делаете это:

ExternalClassNotMyCode c = new ExternalClassNotMyCode();
try {
    c.doSomething( () => { throw new Exception(); } );
}
catch ( Exception ex ) {}

doSomething вызывает там вашу анонимную функцию, и эта функция выдает исключение ...

Обратите внимание, что это «необработанное исключение» согласно Visual Studio, если «Включить только мой код» включен. Также обратите внимание, что он останавливается, как если бы это была точка останова в режиме отладки, но в среде, не связанной с отладкой или производственной средой, код полностью действителен и работает так, как ожидалось. Кроме того, если вы просто «продолжите» в отладчике, приложение продолжит свою работу весело (это не остановит поток). Это считается «необработанным», потому что исключение распространяется через фрейм стека, который НЕ находится в вашем коде (то есть во внешней библиотеке). Если вы спросите меня, это паршивая. Измените это поведение по умолчанию Microsoft. Это вполне допустимый случай использования исключений для управления логикой программы. Иногда вы не можете изменить стороннюю библиотеку, чтобы она работала по-другому, и это очень полезный способ выполнения многих задач.

Возьмем, к примеру, MyBatis, вы можете использовать этот метод, чтобы остановить обработку записей, которые собираются вызовом SqlMapper.QueryWithRowDelegate.

Если вы хотите предложить изменить способ работы Visual Studio, могу ли я предложить Microsoft Connect?

Andrew Barber 20.01.2012 23:38

В первую очередь я хочу объяснить поведение, которое отсутствовало в этой теме. Тот факт, что я добавил комментарий к ожидаемому поведению, вполне приемлем, если вы спросите меня.

Tony Schwartz 20.01.2012 23:42

Я бы обсудил это, но мой комментарий был не в этом. Мой комментарий был адресован сделать вам предложение, если вы серьезно относитесь к проблеме.

Andrew Barber 20.01.2012 23:44

Если вы используете com-объекты в своем проекте и пытаетесь поймать блоки, чтобы не улавливать исключения, вам необходимо отключить «Инструменты» / «Отладка» / «Прерывание», когда исключения пересекают домен приложения или управляемые / собственные границы (только управляемые).

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