Подтвердить что ты не робот

Являются ли исключения и возвратные заявления единственными возможными ранними выходами в С#?

Например, мне интересно, если в следующем коде я могу быть уверен, что будут выполняться либо Foo(), либо Bar().

try {
    ... // Assume there is not return statement here
    Foo();
} catch (Exception e) {
    Bar();
}

Я хорошо знаком с блоками finally и не нуждаюсь в объяснении этой функции.

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

4b9b3361

Ответ 1

Предположим, что у нас есть несколько кодов:

try
{
    /*Breaking statement goes here*/

    Foo();
}
catch (Exception ex)
{
    Bar();
}
finally
{
    Baz();
}

Я разделил бы разрывы на 3 общие причины:

Ответ 2

Существуют также способы "сгореть дома" для остановки приложения:

Environment.Exit(int code);
Environment.FailFast(string message);
Thread.CurrentThread.Abort();
AppDomain.Unload(AppDomain.CurrentDomain);

Для удовольствия, здесь другое:)

[DllImport("kernel32.dll",SetLastError = true)]
static extern bool WriteProcessMemory(
      IntPtr hProcess, 
      IntPtr lpBaseAddress, 
      byte [] lpBuffer, 
      uint nSize, 
      out UIntPtr lpNumberOfBytesWritten);

var myProcess = Process.GetCurrentProcess();
var hProcess = myProcess.Handle;
var rnd = new Random();
while(true)
{
    var writeTo = new IntPtr((int)rnd.Next(0, int.MaxValue));
    var toWrite = new byte[1024];
    UIntPtr written;
    WriteProcessMemory(
        hProcess, 
        writeTo, 
        toWrite, 
        (uint)toWrite.Length, 
        out written);
}

Из любопытства и подталкивания возьмите их за тест-драйв!

Наша испытательная установка:

    static void Main(string[] args)
    {
        Trace.Listeners.Add(new ConsoleTraceListener());
        AppDomain.CurrentDomain.UnhandledException += OnNoes;
        try
        {
            // INSERT BURN STATEMENT
            Foo();
        }
        catch (Exception e)
        {
            Bar();
        }
        finally
        {
            Baz();
        }
    }

    static void Foo()
    {
        Trace.WriteLine("I AM FOO!");
    }
    static void Bar()
    {
        Trace.WriteLine("I AM BAR!");
    }
    static void Baz()
    {
        Trace.WriteLine("I AM BAZ!");
    }
    static void OnNoes(object sender, UnhandledExceptionEventArgs e)
    {
        Trace.WriteLine("OhNoes!");
    }

Результаты!

Заявление о записи:

Thread.CurrentThread.Abort();

Вывод:

I AM BAR!
I AM BAZ!

Заявление о записи:

AppDomain.Unload(AppDomain.CurrentDomain);

Вывод:

I AM BAR!
I AM BAZ!

Заявление о записи:

Environment.Exit(-1);

Вывод:

Nothing! No trace output at all!

Заявление о записи:

Environment.FailFast("Burn!!!");

Вывод:

Application crash! A FatalExecutionEngineError was thrown, 
which was not caught by any block/handler. No trace output.

Итак, вы идете! Какие? Я пропустил один?

Заявление о записи:

Splode();

Где "Splode":

    static void Splode()
    {
        var myProcess = Process.GetCurrentProcess();
        var hProcess = myProcess.Handle;
        var rnd = new Random();
        while (true)
        {
            var writeTo = new IntPtr((int)rnd.Next(0, int.MaxValue));
            var toWrite = new byte[1024];
            UIntPtr written;
            WriteProcessMemory(
                hProcess,
                writeTo,
                toWrite,
                (uint)toWrite.Length,
                out written);
        }            
    }

Вывод:

Application crash! A FatalExecutionEngineError was thrown, 
which was not caught by any block/handler. No trace output.
Crashed Visual Studio while running attached!

Ответ 3

Да... наиболее очевидными являются await, yield break/yield return, goto, if(false) и т.д., как указано в комментариях. Но все эти утверждения/выражения должны быть написаны самим собой, в методе, содержащем ваш оператор try, поэтому вам не нужно беспокоиться о них.

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

В спецификации языка С# указано, что единственными вещами, которые вы можете бросить, являются либо экземпляры класса Exception, либо литерал null (в этом случае бросается a NullReferenceException). Найдено в §8.9.5:

Выражение [throw] должно означать значение типа класса System.Exception, типа класса, которое происходит из System.Exception или типа параметра типа, которое имеет System.Exception(или его подкласс) как его эффективное базовый класс. Если оценка выражения вызывает нуль, вместо этого возникает исключение System.NullReferenceException.

Однако это ограничение ограничивает только код С#. Код С# скомпилирован в промежуточный язык, который не ограничен таким образом. Также в спецификации языка С#, §8.10:

Некоторые языки программирования могут поддерживать исключения, которые не могут быть представлены в качестве объекта, производного от исключения System.Exception, хотя такие исключения никогда не могут быть сгенерированы кодом С#.

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

try
{
    //...
    Foo();
}
catch
{
    Bar();
}

ПРИМЕЧАНИЕ. Этот метод применяется только в том случае, если вы скомпилируете .NET Framework до версии 2.0. Начиная с этой версии, CLR обертывает брошенный объект в RuntimeWrappedException. Спасибо, svick!

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

Ответ 4

Есть также несколько других опций (один из которых упоминается в The Daily WTF, когда компания считала, что транзакции поймали все), а именно: отключение операционной системы, уничтожение задачи и потеря мощности в машине (не смейтесь, Бывает). Некоторые из них вы можете обрабатывать с помощью событий Form_Closing, например (выключение ОС), но некоторые из них вы просто не можете. Операционная система и другие приложения (например, VS при ее сбое) оборачиваются этими обстоятельствами, сохраняя временное состояние каждые X минут. Если это состояние существует, приложение неожиданно прекращается. Если такое состояние не существует, приложение завершилось чисто и данные были сохранены правильно.