Cách thích hợp để hiển thị đầy đủ InternalException là gì?


155

Cách thích hợp để thể hiện đầy đủ của tôi là gì InnerException .

Tôi thấy rằng một số InternalExceptions của tôi có cái khác InnerException và nó đi khá sâu.

Sẽ InnerException.ToString()làm công việc cho tôi hay tôi cần phải lặp đi lặp lại InnerExceptionsvà xây dựng Stringvới StringBuilder?


Tại sao bạn cần thể hiện ngoại lệ bên trong ??
Akram Shahda

26
@Akram vì phần lớn thời gian là ngoại lệ thú vị. Một ví dụ là XmlSerializer, nó sẽ ném một UnlimitedOperationException bất cứ khi nào có sự cố. Những gì đã sai là trong ngoại lệ bên trong.
adrianm

4
@AkramShahda Chà, có lẽ bạn muốn sử dụng phương thức này trong nhật ký của mình?
cederlof

Câu trả lời:


239

Bạn có thể chỉ cần in exception.ToString()- nó cũng sẽ bao gồm toàn văn cho tất cả các InnerExceptions lồng nhau .


18
Điều này bao gồm cả tải những
thứ nhảm nhí

chỉ vì cô đọng mà bạn không thực sự cần .ToString (), chỉ cần sử dụng ngoại lệ cũng sẽ làm như vậy.
Alex Stephens

3
@AlexStephens bạn đúng, nhưng chỉ khi bạn có một chuỗi ẩn "thành chuỗi" vì một số lý do, như chuỗi trước: "bla" + ngoại lệ
oo_dev

1
FYI: nó sẽ không gọi một ToStringphương thức tùy chỉnh cho các ngoại lệ bên trong như chi tiết trong Tại sao không System.Exception.ToString gọi ảo ToString cho các ngoại lệ bên trong? .
Jeff B

45

Chỉ dùng exception.ToString()

http://msdn.microsoft.com/en-us/l Library / system.exception.tostring.aspx

Việc triển khai mặc định của ToString có được tên của lớp đã ném ngoại lệ hiện tại, thông báo, kết quả của việc gọi ToString về ngoại lệ bên trong và kết quả của việc gọi môi trường.StackTrace. Nếu bất kỳ thành viên nào trong số này là null, giá trị của nó không được bao gồm trong chuỗi trả về.

Nếu không có thông báo lỗi hoặc nếu đó là một chuỗi trống (""), thì không có thông báo lỗi nào được trả về. Tên của ngoại lệ bên trong và dấu vết ngăn xếp chỉ được trả về nếu chúng không phải là null.

ngoại lệ.ToString () cũng sẽ gọi .ToString () trên ngoại lệ bên trong của ngoại lệ đó, v.v.


45

Tôi thường làm như thế này để loại bỏ hầu hết tiếng ồn:

void LogException(Exception error) {
    Exception realerror = error;
    while (realerror.InnerException != null)
        realerror = realerror.InnerException;

    Console.WriteLine(realerror.ToString())
}    

Chỉnh sửa: Tôi quên mất câu trả lời này và ngạc nhiên không ai chỉ ra rằng bạn chỉ có thể làm

void LogException(Exception error) {
    Console.WriteLine(error.GetBaseException().ToString())
}    

Phương pháp này che giấu mọi thứ trừ ngoại lệ sâu nhất bên trong. Nếu đó là một thứ gì đó trần tục như lỗi "Chia cho số 0", thì không rõ nó xảy ra ở đâu và điều gì dẫn đến nó. Rõ ràng, một dấu vết ngăn xếp đầy đủ thường là một sự quá mức lộn xộn, nhưng chỉ đọc ngoại lệ bên trong là cực đoan khác. Câu trả lời của người dùng là tốt hơn nhiều. Bạn nhận được mọi thông báo ngoại lệ trong ngăn xếp mà không có dấu vết khó chịu.
JamesHoux

1
@JamesHoux Câu trả lời nào là "user4956982"? Không thể tìm thấy anh ta ở đây.
maracuja-Juice

Người dùng4956982 là ThomazMoura, xem: stackoverflow.com/users/3016982/thomazmoura
Apfelkuacha

@JamesHoux, ngoại lệ bên trong có một ngăn xếp đầy đủ cho biết lỗi xảy ra ở đâu và điều gì dẫn đến nó. Không hiểu những thông tin bổ sung nào bạn nhận được từ dấu vết ngăn xếp bị xóa. Thông điệp ngoại lệ là một điều khác và nó có thể hữu ích để thu thập tất cả chúng.
adrianm

2
Tại sao bạn không sử dụng error.GetBaseException(). Tôi tin rằng điều này cũng tương tự ...
Robba

37

Câu trả lời của @ Jon là giải pháp tốt nhất khi bạn muốn có đầy đủ chi tiết (tất cả các tin nhắn và dấu vết ngăn xếp) và đề xuất.

Tuy nhiên, có thể có trường hợp khi bạn chỉ muốn các thông điệp bên trong và đối với những trường hợp này, tôi sử dụng phương thức tiện ích mở rộng sau:

public static class ExceptionExtensions
{
    public static string GetFullMessage(this Exception ex)
    {
        return ex.InnerException == null 
             ? ex.Message 
             : ex.Message + " --> " + ex.InnerException.GetFullMessage();
    }
}

Tôi thường sử dụng phương pháp này khi tôi có các trình nghe khác nhau để theo dõi và ghi nhật ký và muốn có các quan điểm khác nhau về chúng. Bằng cách đó, tôi có thể có một người nghe gửi toàn bộ lỗi với dấu vết ngăn xếp qua email đến nhóm nhà phát triển để gỡ lỗi bằng .ToString()phương thức và một người ghi nhật ký vào tệp có lịch sử của tất cả các lỗi xảy ra mỗi ngày mà không có dấu vết ngăn xếp với các .GetFullMessage()phương pháp.


7
FYI Nếu exlà một AggregateException, không có ngoại lệ bên trong nào sẽ được đưa vào sản phẩm này
kornman00

3
Đây phải là một phương pháp .NET stock. Mọi người nên sử dụng cái này
JamesHoux

9

Để in đẹp chỉ Messagelà một phần của ngoại lệ sâu sắc, bạn có thể làm một cái gì đó như thế này:

public static string ToFormattedString(this Exception exception)
{
    IEnumerable<string> messages = exception
        .GetAllExceptions()
        .Where(e => !String.IsNullOrWhiteSpace(e.Message))
        .Select(e => e.Message.Trim());
    string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
    return flattened;
}

public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
    yield return exception;

    if (exception is AggregateException aggrEx)
    {
        foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
        {
            yield return innerEx;
        }
    }
    else if (exception.InnerException != null)
    {
        foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
        {
            yield return innerEx;
        }
    }
}

Điều này đệ quy đi qua tất cả các ngoại lệ bên trong (bao gồm cả trường hợp của AggregateExceptions) để in tất cả các thuộc Messagetính có trong chúng, được phân định bằng dấu ngắt dòng.

Ví dụ

var outerAggrEx = new AggregateException(
    "Outer aggr ex occurred.",
    new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
    new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());

Bên ngoài aggr ex xảy ra.
Nội aggr ex.
Số không đúng định dạng.
Truy cập tập tin trái phép.
Không phải quản trị viên.


Bạn sẽ cần lắng nghe các thuộc tính Ngoại lệ khác để biết thêm chi tiết. Ví dụ Datasẽ có một số thông tin. Bạn có thể làm:

foreach (DictionaryEntry kvp in exception.Data)

Để có được tất cả các thuộc tính dẫn xuất (không phải trên Exceptionlớp cơ sở ), bạn có thể làm:

exception
    .GetType()
    .GetProperties()
    .Where(p => p.CanRead)
    .Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));

+1, Điều này gần như chính xác giống như tôi làm. Hãy xem xét để tìm kiếm một tài sản thực hiện IEnumerable<Exception>thay vì mã hóa cứng AggregrateExceptionđể xử lý các loại tương tự khác. Cũng loại trừ p.IsSpecialNamepi.GetIndexParameters().Length != 0để tránh các vấn đề. Bao gồm tên loại ngoại lệ trong đầu ra cũng là một ý tưởng hay
adrianm

@adrianm điểm tốt về kiểm tra thông tin tài sản. Về việc kiểm tra bộ sưu tập các ngoại lệ, tất cả là về nơi bạn muốn vẽ đường. Chắc chắn điều đó cũng có thể được thực hiện ..
nawfal

4

Tôi làm:

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
      return msg;
    }
  }
}

Điều này "in đẹp" tất cả các trường hợp ngoại lệ bên trong và cũng xử lý AggregateExceptions và các trường hợp trong đó InternalException.Message giống như Tin nhắn


3

Nếu bạn muốn thông tin về tất cả các ngoại lệ thì sử dụng exception.ToString(). Nó sẽ thu thập dữ liệu từ tất cả các ngoại lệ bên trong.

Nếu bạn chỉ muốn ngoại lệ ban đầu thì sử dụng exception.GetBaseException().ToString(). Điều này sẽ giúp bạn có ngoại lệ đầu tiên, ví dụ ngoại lệ sâu nhất bên trong hoặc ngoại lệ hiện tại nếu không có ngoại lệ bên trong.

Thí dụ:

try {
    Exception ex1 = new Exception( "Original" );
    Exception ex2 = new Exception( "Second", ex1 );
    Exception ex3 = new Exception( "Third", ex2 );
    throw ex3;
} catch( Exception ex ) {
    // ex => ex3
    Exception baseEx = ex.GetBaseException(); // => ex1
}

2

tích lũy trên câu trả lời của nawfal.

Khi sử dụng câu trả lời của anh ta có một biến aggrEx bị thiếu, tôi đã thêm nó.

tập tin ExceptionExtenstions. class:

// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YourNamespace
{
    public static class ExceptionExtensions
    {

        public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
        {
            yield return exception;

            if (exception is AggregateException )
            {
                var aggrEx = exception as AggregateException;
                foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
                {
                    yield return innerEx;
                }
            }
            else if (exception.InnerException != null)
            {
                foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
                {
                    yield return innerEx;
                }
            }
        }


        public static string ToFormattedString(this Exception exception)
        {
            IEnumerable<string> messages = exception
                .GetAllExceptions()
                .Where(e => !String.IsNullOrWhiteSpace(e.Message))
                .Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
            string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
            return flattened;
        }
    }
}

Tôi đã có một ngoại lệ vì:e.StackTrace == null
Andrei Krasnutski

1
Tôi đã cập nhật .Select (e => e.Message.Trim () + "\ r \ n" + (e.StackTrace! = Null? StackTrace.Trim (): "")); có lẽ điều này sẽ giúp
Shimon Doodkin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.