Mùi thiết kế, thực hành kém trong đệ quy? sau khi tôi thấy việc chia sẻ lại đề xuất cải tiến, tôi nhanh chóng xem xét trên google. Đã thấy nhiều nhận xét xung quanh việc đệ quy lại đuôi cho các lần lặp lại và đề cập đến nó như một mùi thiết kế.Tại sao lặp lại nên được sử dụng thay vì đệ quy đuôi?
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;
}
}
CHỈNH SỬA: Được gửi vào bình luận điều trị trình biên dịch C#. Có vẻ như nó đang đệ quy bây giờ
Mục tiêu .net 4.5. C# 5.0
ILDASM Output cho phiên bản đệ quy đuôi: Hiển thị cuộc gọi đệ quy và không lặp
.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
Lưu ý rằng, trong khi CLR hỗ trợ các cuộc gọi đuôi, [trình biên dịch C# không phát ra chúng] (http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/) (thời gian qua tôi đã kiểm tra). Trong mọi trường hợp, nó không chắc rằng bạn sẽ thổi các ngăn xếp với cấu trúc đặc biệt này, và hiệu suất không thực sự là một vấn đề vì bạn đã đối phó với ngoại lệ anyway. –
Tôi sẽ từ chối rằng 'while' loop ủng hộ một cái gì đó gần gũi hơn với' while (ex! = Null) {Debug.WriteLine (ex.Message); ex = ex.InnerException} '. – Kevin
Hãy xem xét những gì xảy ra khi sử dụng đệ quy đuôi từ góc độ hiệu suất. Chúng ta cần tạo một khung ngăn xếp, sao chép một số thứ vào và gọi rồi gọi hàm. Tùy thuộc vào đệ quy, điều này có thể dẫn đến một chồng bị thổi (mặc dù không có trong ví dụ này) và hiệu suất tồi tệ hơn mà không lặp lại đệ quy – rileyberton