отладка асинхронного C # в visual studio; нарушая исключения, как и ожидалось - PullRequest
0 голосов
/ 23 марта 2019

Я изо всех сил пытаюсь понять, как использовать Visual Studio для разумной отладки асинхронного кода, поскольку он не нарушает того, чего я хочу.Например, в этом коде:

using System;
using System.Threading.Tasks;

namespace TestNS{
    class Program {
        static void Main(string[] args) {
            Foo().Wait(); // sadly, it breaks here
        }

        static async Task Foo() {
            var foo = 42;
            if (foo == 42) {
                throw new Exception(); // want it to break here
            }
        }
    }
}

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

Я понимаю, что основная проблема заключается в том, что исключения технически обрабатываются скрытым асинхронным кодом, поэтомуVS не считает их необработанными.Конечно, больше никому не нравится это поведение, и есть способ сообщить VS, что исключения, которые всплывают до асинхронного вызова, на самом деле не перехватываются ... Я пытался превратить «просто мой код», «сломать, когда это исключениевыбрасывается "и т. д., но не помогает.

Я не ищу решения, которое включает редактирование моего кода или добавление точек останова вручную.Аналогичным образом, обработка определенных исключений особым образом также не является реальным решением.Не все исключения, на которые я хотел бы остановиться, были из моего собственного кода;часто это происходит из-за отсутствующего ключа в словаре или чего-то подобного.Неожиданные исключения случаются все время при разработке кода, и я хочу легко увидеть это состояние программы без ручного размещения точек останова и / или кода try / catch, перезапуска программы , ручного продвижения программы до тех пор, пока я не получук функции.И это все при условии, что я могу даже заставить его снова сработать, когда я ничего не знаю о том, почему это произошло в первую очередь.И затем сделайте это для каждого исключения, которое когда-либо может произойти во время разработки.

Кроме того, если вы посмотрите на AggregateException, который возвращается, то даже нет хорошего способавыяснить, откуда это исключение.Вам нужно «просмотреть детали», затем развернуть исключение, развернуть внутреннее исключение, навести курсор на трассировку стека, запомнить файл и номер строки , закрыть детали, перейти в нужное место вручную,а теперь поставьте точки останова вручную и отладьте вручную.Почему система не может использовать эту трассировку стека, чтобы делать правильные вещи?

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

Ответы [ 2 ]

2 голосов
/ 23 марта 2019

вам нужно активировать исключение Common Language Runtime, используя CTRL + ALT + E, как показано на рисунке ниже.

enter image description here

0 голосов
/ 23 марта 2019

Вам необходимо включить Общие языковые исключения во время выполнения , поскольку @sayah уже ответил.

Тем не менее, вы должны использовать async до самого конца:

static async Task Main(string[] args) {
    await Foo();
}

Это покажет вам исключения, где они происходят.

Стивен Клири написал хорошую статью о причинах, по которым вы хотите использовать async наверх.

Взгляните на этот пример:

internal class Program
{
    //static void Main(string[] args)
    //{
    //    try
    //    {
    //        Foo().Wait();
    //    }
    //    catch (FooException)
    //    {
    //        Console.WriteLine("Yep, its a Foo Exception");
    //    }
    //    catch (AggregateException)
    //    {

    //        Console.WriteLine("Damn it, we got an Aggregate");
    //    }

    //    Console.ReadKey();
    //}

    static async Task Main(string[] args)
    {
        try
        {
            await Foo();
        }
        catch (FooException)
        {
            Console.WriteLine("Yep, its a Foo Exception");
        }
        catch (AggregateException)
        {

            Console.WriteLine("Damn it, we got an Aggregate");
        }

        Console.ReadKey();
    }


    class FooException : Exception
    {
    }

    static async Task<int> Foo()
    {
        await Task.Delay(100);
        var foo = 42;
        if (foo == 42) {
            throw new FooException(); // want it to break here
        }

        return 43;
    }
}

Если вы обменяете прокомментированный Main(), вы увидите, что вы получаете AggregateException в методе не async, в то время как вы получаете FooException в асинхронном методе.


Примечание : Если это не работает для вас, вам нужно установить уровень языка в расширенных настройках проекта на C# 7.1 или выше, как объяснено .

  • Щелкните правой кнопкой мыши свой проект и выберите Свойства

Build

  • Перейдите к build settings и нажмите advanced , чтобы установить языковую версию на C# 7.1 или более позднюю

Advanced

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