Странное поведение с предложениями catch - PullRequest
0 голосов
/ 24 апреля 2020

Я столкнулся со странной проблемой с отфильтрованным предложением catch:

catch (System.Net.Http.HttpRequestException ex)
{
    ManagerHelper.Current.ExceptionHandler.Log($"random message",
                log4net.Core.Level.Error, ex: ex);
}
catch (ArgumentNullException ex)
{
    ManagerHelper.Current.ExceptionHandler.Log($"random message for null value",
                log4net.Core.Level.Error, ex: ex);
}
catch (Exception ex) when (!(ex is System.Net.Http.HttpRequestException) && !(ex is ArgumentNullException))
{
    ManagerHelper.Current.ExceptionHandler.Log($"random message for other 
   exception", log4net.Core.Level.Error, ex: ex);
}

На самом деле, когда я выкидываю исключение HttpRequestException, ожидаемое поведение будет заключаться в обнаружении указанной ошибки c. По неизвестной причине, даже если результат предложения where ложен, я вписываюсь фактически в catch (Exception ex), а не в catch (System. Net .Http.HttpRequestException ex).

В ближайшем окне :

! (Например, System. Net .Http.HttpRequestException) &&! (Ex является ArgumentNullException) => false

У кого-нибудь есть объяснение этого ?

Заранее спасибо за ваши ответы и / или советы.

Отредактировал образец, чтобы сделать его более понятным.

Еще одна попытка, которую я сделал:

 catch (Exception ex)
{
    Type varType = ex.GetType();
    if (ex is System.Net.Http.HttpRequestException)
      ManagerHelper.Current.ExceptionHandler.Log($"random message", log4net.Core.Level.Error, ex: ex as 
      System.Net.Http.HttpRequestException);
    else if (ex is ArgumentNullException)
       ManagerHelper.Current.ExceptionHandler.Log($"random message for null value", log4net.Core.Level.Error, ex: ex as 
       ArgumentNullException); 
    else
       ManagerHelper.Current.ExceptionHandler.Log($"random message for other value", log4net.Core.Level.Error, ex: ex);
}

содержимое varType:

{Name = "HttpRequestException" FullName = "System. Net .Http.HttpRequestException"}

Первое, если результатом является false и код вводится в операторе else при отладке.

, если я делаю:

varType == typeof (System. Net .Http.HttpRequestException)

Результат верен.

Ответы [ 2 ]

7 голосов
/ 24 апреля 2020

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

Ваше ожидание полностью противоречит реальность; Мне интересно знать, как люди приходят к таким ложным убеждениям о языках программирования, поэтому, если у вас есть минутка, чтобы оставить комментарий, объясняющий, как вы пришли к этому ложному убеждению, я был бы признателен.

Точная природа того, как ваши убеждения ошибочны, не очень ясна. Похоже, вы верите в одну из двух ложных вещей: либо (1) выполняется каждый соответствующий блок catch, а не только первый, или (2) повторный бросок в блоке catch, который находится вне try block вызывает выполнение другого блока catch "down down".

Документированное и разработанное поведение C# в отношении обработки исключений состоит в том, что процесс обработки исключений происходит следующим образом:

  • Исключение выдается
  • среда выполнения анализирует стек, чтобы найти вмещающие блоки try с предложениями catch.
  • Кадры стека перечисляются в порядке от самого последнего к наименее последнему.
  • Кадр стека может быть связан с вызовом, который имеет несколько окружающие блоки try с предложениями catch вокруг сайта вызова. В этом случае блоки try также проверяются в порядке от самого внутреннего к внешнему.
  • Для каждого включающего в себя блока try с предложением catch элементы catch catch проверяются в программном порядке сверху вниз.
  • Неохраняемое предложение catch соответствует всем. Предложение catch с типом соответствует исключению этого типа. Предложение catch с фильтром выполняет фильтр. Обратите внимание, что фильтры выполняются перед окончательной блокировкой .
  • Как только определенное совпадение с first определено, поиск останавливается.

OK Таким образом, в этот момент произошла одна из двух вещей. Либо мы определили блок catch, связанный с этим исключением, либо такого блока catch нет. Если такого блока нет, то поведение программы становится неопределенным . В этот момент среда выполнения может решить сделать несколько вещей, включая запуск отладчиков, запуск или отсутствие запуска блоков finally, запуск или отсутствие запуска обработчиков событий «необработанное исключение» и т. Д. Обратитесь к документации времени выполнения для деталей; это не охватывается спецификацией C#.

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

Представление о том, что каждый соответствующий совпадающий блок catch будет выполняться, просто ложно, поэтому остановите веря в это. И представление о том, что бросок в блоке захвата каким-то образом пойман, как если бы он был брошен изнутри try, также неверно, так что не верьте этому.

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

try 
{
  try
  {
    do the stuff
  }
  catch (your type) when your filter
  {
     do more stuff
     throw; // re-throw to execute the outer "Pokemon" block.
  }
}
catch
{
  now this always runs on exception
}

Имеет ли это смысл?

1 голос
/ 24 апреля 2020

Вы должны переписать свой код как тест, чтобы подтвердить (или опровергнуть) ваше понимание. Обратите внимание, что в блоке try вы можете протестировать каждое исключение, раскомментировав:

using System;
using System.Net.Http;

namespace junk
{
    class Program
    {
        static void Main(string[] args)
        {
            TestEx();
            Console.ReadKey();
        }

        static void TestEx()
        {
            try
            {
                //throw new HttpRequestException();
                //throw new ArgumentNullException();
                throw new Exception();
            }
            catch (HttpRequestException ex)
            {
                Log(ex, "HttpRequestException");
            }
            catch (ArgumentNullException ex)
            {
                Log(ex, "ArgumentNullException");
            }
            catch (Exception ex) when(!(ex is System.Net.Http.HttpRequestException) && !(ex is ArgumentNullException))
            {
                Log(ex, "Exception");
            }
            catch
            {
                Log("The way I understand it, this really should never be executed.");
            }
        }

        static void Log(string source)
        {
            Console.WriteLine(source);
        }

        static void Log(Exception ex, string source)
        {
            //ManagerHelper.Current.ExceptionHandler.Log($"random message", 
            //log4net.Core.Level.Error, ex: ex);
            Console.WriteLine(source + ": " + ex.Message);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...