异常和返回语句是C​​#中唯一可能的早期退出吗?

时间:2013-03-06 22:32:04

标签: c# .net

例如,我很好奇,如果在以下代码中,我可以放心,Foo()Bar()将被执行。

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

我非常熟悉finally块,并且不需要对该功能进行解释。

我问,因为Throwable的存在,上面的代码在Java中工作,我发现了很难。

4 个答案:

答案 0 :(得分:6)

还有“烧毁房子”的方式来停止申请:

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!

答案 1 :(得分:5)

是的......最明显的是awaityield break / yield returngotoif(false)等,如评论中所述。但是所有这些语句/表达式都必须由您自己编写,包含您的try语句的方法,因此您不必担心它们。

然而,即使除此之外, 是一种退出方式而不会抛出异常或返回(或运行这两种方法中的任何一种)。那就是......抛出一些不例外的东西。

C#语言规范指出,您可以抛出的唯一内容是类Exception的实例,或null文字(在这种情况下抛出NullReferenceException。)在§8.9.5中:

  

[throw]表达式必须表示类型System.Exception的值,该类型派生自System.Exception的类类型或具有System.Exception(或其子类)作为其有效的类型参数类型基类。如果表达式的计算结果为null,则抛出System.NullReferenceException。

但是,此限制仅限制C#代码。 C#代码编译成中间语言,不受此限制。也可以在C#语言规范中找到,§8.10:

  

某些编程语言可能支持不能表示为从System.Exception派生的对象的异常,尽管这些异常永远不会由C#代码生成。

为了捕获这些异常,您需要使用一般的catch子句,如下所示:

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

注意:此方法仅适用于在2.0版之前编译为.NET框架的情况。从该版本开始,CLR将抛出的对象包装在RuntimeWrappedException中。谢谢,svick!

此外,还有一些人提到杀死这个过程,或者抛出一个StackOverflowException,两者都可以很好地完成这项任务。除了这些之外还有其他方法,但我不这么认为(除了突然拔掉电脑,天堂禁止。)希望这有帮助! --Brandon

答案 2 :(得分:3)

假设我们有以下代码:

try
{
    /*Breaking statement goes here*/

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

我会将破坏者分为三个常见原因:

  1. 代码流程声明:

    1.1。 return:Foo( - );酒吧(-);巴兹(+);

    1.2。 goto:Foo( - );酒吧(-);巴兹(+);

    1.3。 if(false):Foo( - );酒吧(-);巴兹(+);

    1.4。 while(true){}:Foo( - );酒吧(-);巴兹( - );

    1.5。 yield return,如果方法返回IEnumerable并且yield return位于try块之前:Foo( - );酒吧(-);巴兹( - );

    1.6。 yield break,如果该方法返回IEnumerable:Foo( - );酒吧(-);巴兹( - );

    1.7。 break,如果代码被循环包装:Foo( - );酒吧(-);巴兹(+);

    1.8。 continue,如果代码被循环包装:Foo( - );酒吧(-);巴兹(+);

  2. 进程/域/线程终止。

    2.1。 Process.GetCurrentProcess().Kill():Foo( - );酒吧(-);巴兹( - );

    2.2。 Environment.Exit(0):Foo( - );酒吧(-);巴兹( - );

    2.3。 Environment.FailFast(""):Foo( - );酒吧(-);巴兹( - );

    2.4。 AppDomain.Unload(AppDomain.CurrentDomain):Foo( - );巴(+);巴兹(+);

    2.5。 Thread.CurrentThread.Abort():Foo( - );巴(+);巴兹(+);

  3. 未处理的例外情况。

    3.1。 .NET 2.0之前的非托管代码中的异常:Foo( - );酒吧(-);巴兹(+);

    3.2。自.NET 2.0以来非托管代码中的异常:Foo( - );巴(+);巴兹(+);

    3.3。自.NET 4.0以来已损坏的进程状态异常(也未指定<legacyCorruptedStateExceptionsPolicy> HandleProcessCorruptedStateExceptionsAttribute):Foo( - );酒吧(-);巴兹(+);

    3.4。在.NET 4.0或<legacyCorruptedStateExceptionsPolicy>HandleProcessCorruptedStateExceptionsAttribute之前指定了损坏的进程状态异常:Foo( - );巴(+);巴兹(+);

    3.5。自.NET 2.0和<legacyUnhandledExceptionPolicy>以来的另一个线程中的异常未启用:Foo( - );酒吧(-);巴兹( - );

    3.6。启用.NET 2.0或<legacyUnhandledExceptionPolicy>之前的另一个线程中的异常:Foo(+);酒吧(-);巴兹(+);

答案 3 :(得分:1)

还有其他几个选项(在每日WTF中提到一个公司认为交易捕获了所有内容时),即操作系统关闭,任务被杀死以及机器中的电源丢失(不要笑) ,它发生了)。其中一些你可以使用Form_Closing事件干净地处理(例如OS关闭)但有些你不能。操作系统和其他应用程序(例如,VS崩溃时)通过每隔X分钟保留一个临时状态来解决这些情况。如果该状态存在,则应用程序意外终止。如果这样的状态不存在,那么应用程序就会干净地退出并正确保存数据。