Was ist der Design-Geruch, schlechte Übung in Rekursion? Sobald ich Resharper Verbesserungen sah sah ich schnell auf google. Ich habe zahlreiche Kommentare gesehen, wie ich die Tail-Rekursion zu Iterationen re-factorisieren und als Design-Geruch bezeichnen kann.Warum sollte die Iteration anstelle der Tail-Rekursion verwendet werden?
public static void DebugOutput2(Exception ex) {
if (ex == null) {
return;
}
Debug.WriteLine(ex.Message);
if (ex.InnerException != null) {
DebugOutput2(ex.InnerException);
}
}
// WAS REFACTORED TO
public static void DebugOutput(Exception ex) {
if (ex == null) {
return;
}
while (true) {
Debug.WriteLine(ex.Message);
if (ex.InnerException != null) {
ex = ex.InnerException;
continue;
}
break;
}
}
EDIT: basierend auf C# Compiler Behandlung Kommentar. Sieht so aus, als ob es jetzt rekursiv ist
Target .net 4.5. C# 5.0
ILDASM Ausgang für Endrekursion Version: Zeigt rekursiven Aufruf und nicht die Iteration
.method public hidebysig static void DebugOutput(class [mscorlib]System.Exception ex) cil managed
{
// Code size 54 (0x36)
.maxstack 2
.locals init ([0] bool CS$4$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: ceq
IL_0005: ldc.i4.0
IL_0006: ceq
IL_0008: stloc.0
IL_0009: ldloc.0
IL_000a: brtrue.s IL_000e
IL_000c: br.s IL_0035
IL_000e: ldarg.0
IL_000f: callvirt instance string [mscorlib]System.Exception::get_Message()
IL_0014: call void [System]System.Diagnostics.Debug::WriteLine(string)
IL_0019: nop
IL_001a: ldarg.0
IL_001b: callvirt instance class [mscorlib]System.Exception [mscorlib]System.Exception::get_InnerException()
IL_0020: ldnull
IL_0021: ceq
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: brtrue.s IL_0035
IL_0027: nop
IL_0028: ldarg.0
IL_0029: callvirt instance class [mscorlib]System.Exception [mscorlib]System.Exception::get_InnerException()
IL_002e: call void ca1.Program::DebugOutput(class [mscorlib]System.Exception)
IL_0033: nop
IL_0034: nop
IL_0035: ret
} // end of method Program::DebugOutput
Beachten Sie, dass, während die CLR Tailaufrufe unterstützt, [der C# -Compiler gibt sie nicht aus] (http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/) (letztes Mal habe ich überprüft). In jedem Fall ist es unwahrscheinlich, dass Sie den Stack mit diesem speziellen Konstrukt sprengen werden, und die Performance ist kein wirkliches Problem, da Sie sowieso ohnehin mit Ausnahmen arbeiten. –
Ich würde diese "while" -Schleife zugunsten von etwas zurückweisen, das näher zu 'while (ex! = Null) {Debug.WriteLine (ex.Message); ex = ex.InnerException}' ist. – Kevin
Überlegen Sie, was mit der Tail-Rekursion in Bezug auf die Leistung geschieht. Wir müssen einen Stapelrahmen erstellen, einige Dinge kopieren und dann die Funktion aufrufen. Abhängig von der Rekursion kann dies zu einem geblasenen Stack führen (obwohl nicht in diesem Beispiel wahrscheinlich) und sicherlich schlechter Performance, die nicht-rekursive Iteration – rileyberton