Frage

beziehe zu viel Dokumentation im Netz, vor allem auf SO, zum Beispiel: Was ist der richtige Weg, um erneut werfen eine Ausnahme in C #? sollte es einen Unterschied zwischen dem, „throw e;“ und "werfen";.

Aber von: http://bartdesmet.net /blogs/bart/archive/2006/03/12/3815.aspx ,

Mit diesem Code:

using System;

class Ex
{
   public static void Main()
  {
  //
  // First test rethrowing the caught exception variable.
  //
  Console.WriteLine("First test");
  try
  {
     ThrowWithVariable();
  }
  catch (Exception ex)
  {
     Console.WriteLine(ex.StackTrace);
  }

  //
  // Second test performing a blind rethrow.
  //
  Console.WriteLine("Second test");
  try
  {
     ThrowWithoutVariable();
  }
  catch (Exception ex)
  {
     Console.WriteLine(ex.StackTrace);
  }
}

 private static void BadGuy()
 {
   //
   // Some nasty behavior.
  //
   throw new Exception();
 }

   private static void ThrowWithVariable()
 {
   try
   {
         BadGuy();
   }
  catch (Exception ex)
  {
     throw ex;
  }
}

   private static void ThrowWithoutVariable()
{
  try
  {
     BadGuy();
  }
  catch
  {
     throw;
  }
   }
}

ergibt folgendes Ergebnis:

$ /cygdrive/c/Windows/Microsoft.NET/Framework/v4.0.30319/csc.exe Test.cs
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1
Copyright (C) Microsoft Corporation. All rights reserved.

$ ./Test.exe
First test
   at Ex.ThrowWithVariable()
   at Ex.Main()
Second test
   at Ex.ThrowWithoutVariable()
   at Ex.Main()

, die mit der Blog-Post in völligem Widerspruch ist.

Die gleiche Art von Ergebnis wird mit dem Code erhalten von: http://crazorsharp.blogspot.com/2009/08/rethrowing-exception-without-resetting.html

Original Frage : Was mache ich falsch

UPDATE : gleiches Ergebnis mit .Net 3.5 / csc.exe 3.5.30729.4926

SUMUP . Sie alle Ihre Antworten waren toll, danke wieder

So ist der Grund effektiv inlining aufgrund der 64-Bit-Jitters.

hatte ich nur eine Antwort zu wählen, und hier ist, warum ich gewählt habe LukeH Antwort:

  • vermutete er das inlining Problem und die Tatsache, es kann zu meiner 64-Bit-Architektur in Beziehung gesetzt werden,

  • er vorgesehen, um die NoInlining Flagge, die der einfachste Weg ist, um dieses Verhalten zu vermeiden.

Doch dieses Problem jetzt steigt eine andere Frage: Dieses Verhalten ist konform mit allen .NET-Spezifikationen: die CLR Einsen und die Programmiersprache C # diejenigen

UPDATE : diese Optimierung scheint konform nach: Werfen VS rethrow: gleiches Ergebnis (danke 0xA3 )

Vielen Dank im Voraus für Ihre Hilfe.

War es hilfreich?

Lösung

Ich kann das Problem nicht replizieren -. Mit .NET 3.5 (32-Bit) gibt mir die gleichen Ergebnisse in Barts Artikel beschrieben

Meine Vermutung ist, dass die .NET-4-Compiler / Jitter - oder vielleicht ist es die 64-Bit-Compiler / Jitter wenn dies zu -3,5 geschieht - wird inlining die BadGuy Methode in den Aufrufen von Methoden. Versuchen Sie, die folgenden MethodImpl Attribut zu BadGuy und sehen, ob das einen Unterschied macht:

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
private static void BadGuy()
{
    //
    // Some nasty behavior.
    //
    throw new Exception();
}

Andere Tipps

Ich habe versucht, diesen Code selbst ausgeführt wird und die Debug-Build funktioniert wie ich erwartet hatte, aber ich habe das gleiche Ergebnis wie Sie in den Release-Build.

vermute ich, was passiert ist, dass der Compiler inlining einfach die BadGuy () -Aufruf mit throw new Exception(); ersetzt hat, weil das die einzige Erklärung ist in BadGuy ().

Wenn Sie die ‚Optimieren Code‘ Option in den Projekteigenschaften ausschalten. -> Build-Bildschirm, dann beide Release- und Debug-Build erzeugt das gleiche Ergebnis, das zeigt BadGuy () an der Spitze des Stack-Trace

Es scheint, dass die JIT-Optimierer tut hier etwas Arbeit. Wie Sie der Call-Stack im zweiten Fall ist zu sehen, anders als im ersten Fall, wenn Sie das Debug-Build ausführen. Doch in dem Release-Build sind beide Call Stacks identisch aufgrund der Optimierung.

Um zu sehen, dass dies auf die Jitter zusammenhängt Sie die Methoden mit einem a href dekorieren <= „http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimplattribute.aspx“ rel = "nofollow noreferrer"> MethodImplAttribute Attribut:

[MethodImpl(MethodImplOptions.NoOptimization)]
private static void ThrowWithoutVariable()
{
    try
    {
        BadGuy();
    }
    catch
    {
        throw;
    }
}

Beachten Sie, dass die IL für ThrowWithoutVariable noch anders und ThrowWithVariable:

.method private hidebysig static void  ThrowWithVariable() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .locals init ([0] class [mscorlib]System.Exception ex)
  .try
  {
    IL_0000:  call       void Ex::BadGuy()
    IL_0005:  leave.s    IL_000a
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_0007:  stloc.0
    IL_0008:  ldloc.0
    IL_0009:  throw
  }  // end handler
  IL_000a:  ret
} // end of method Ex::ThrowWithVariable

.method private hidebysig static void  ThrowWithoutVariable() cil managed
{
  // Code size       11 (0xb)
  .maxstack  1
  .try
  {
    IL_0000:  call       void Ex::BadGuy()
    IL_0005:  leave.s    IL_000a
  }  // end .try
  catch [mscorlib]System.Object 
  {
    IL_0007:  pop
    IL_0008:  rethrow
  }  // end handler
  IL_000a:  ret
} // end of method Ex::ThrowWithoutVariable

Aktualisieren Sie Ihre Follow-up-Frage zu beantworten, ob dies mit der CLI-konform ist Spezifikation

In der Tat gefällig es, und zwar für die JIT-Compiler zu ermöglichen, wichtige Optimierungen zu ermöglichen. Anhang F Staaten auf Seite 52 (Schwerpunkt von mir):

  

Einige CIL Befehle führen implizite   Laufzeitprüfungen, die Speicher zu gewährleisten und   Typsicherheit. Ursprünglich war die CLI   garantiert, dass die Ausnahmen waren   präzise , was bedeutet, dass Programmzustand   erhalten wurde, als eine Ausnahme   geworfen. jedoch die Durchsetzung präzise   Ausnahmen für implizite Kontrollen Marken   einige wichtige Optimierungen   praktisch unmöglich, zu übernehmen.   Programmierer können nun erklären, über ein   benutzerdefiniertes Attribut, das ein Verfahren ist,   „Entspannt“, die besagt, dass Ausnahmen   die sich aus impliziten Laufzeitprüfungen   muss nicht genau sein.

     

Relaxed Kontrollen   bewahren Prüfbarkeit (durch die Erhaltung   Speicher und Sicherheitstyp), während   ermöglicht Optimierungen, die Neuordnungs   Anleitung. Insbesondere ist es   ermöglicht folgende Optimierungen:

     
      
  • Hissen implizite Laufzeit Kontrollen   von Schleifen.
  •   
  • Die Neuanordnung Schleifeniterationen   (Z.B. Vektorisierung und automatische   Multithreading)
  •   
  • Vertauschen Schleifen
  •   
  • Inlining das macht eine inlined   Verfahren nach mindestens so schnell wie die   Äquivalent Makro
  •   

ein Debug-Build verwenden und Sie werden den Unterschied deutlicher sehen. Mit einem Debug-Build zeigt der erste Lauf den Standort als throw ex Linie und die zweite als von dem eigentlichen Aufruf BadGuy. Offensichtlich ist das ‚Problem‘ ist der Aufruf BadGuy -. Nicht der Wurf ab Zeile und Sie werden mit der direkten throw; Aussage weniger Geister jagen

In einem Stapel verfolgt diese seicht die Vorteile sind nicht als immediatley offensichtlich, in einem sehr tief Sie stapeln würde die eigentliche Ursache des Problems Maske und einige Treue verlieren durch manuelle Ausnahme werfen, anstatt den eingebauten Wiederwurf Aussage.

Auf einer Seite zur Kenntnis, fand ich einen Hack auf einem Blog gepostet einmal (ich da die Referenz verloren haben), dass Sie den Anruf-Stack auf rethrow behalten können. Dies ist vor allem dann nützlich, wenn Sie eine Ausnahme in einem Kontext zu fangen (sagen wir, in einem Thread einen asynchronen Vorgang ausgeführt wird) und wollen es in einem anderen erneut auslösen (zum Beispiel in dem anderen Thread, der die asynchrone Operation gestartet). Es nutzt einige undokumentierte Funktionen Erhaltung von Stack-Traces über Remotegrenzen hinweg zu ermöglichen, enthalten.

    //This terrible hack makes sure track trace is preserved if exception is re-thrown
    internal static Exception AppendStackTrace(Exception ex)
    {
        //Fool CLR into appending stack trace information when the exception is re-thrown
        var remoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString",
                                                                 BindingFlags.Instance |
                                                                 BindingFlags.NonPublic);
        if (remoteStackTraceString != null)
            remoteStackTraceString.SetValue(ex, ex.StackTrace + Environment.NewLine);

        return ex;
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top