2009-12-11 3 views
19

У меня есть специальный класс исключений, который содержит некоторые дополнительные поля. Я хочу, чтобы они были выписаны в методе ToString(), но если я реализую свой собственный ToString(), я теряю некоторые другие полезные вещи (например, записывая имя типа исключения, данные внутреннего исключения и трассировку стека).C#: переопределить метод ToString() для пользовательских исключений

Каков наилучший способ/образец для реализации собственного метода ToString() для таких исключений? В идеале он должен повторно использовать существующий механизм, но быть отформатирован таким же образом, как и по умолчанию ToString().

UPDATE: или добавляя слева, добавляя свои собственные поля в base.ToString() текст не является идеальным ИМХО, например

PimTool.Utilities.OERestServiceUnavailableException: test ---> System.InvalidOperationException: inner message 
    --- End of inner exception stack trace --- 
    at PimTool.Tests.Services.OE.OERestClientTests.ExceptionsLogging() in D:\svn\NewPimTool\PimTool.Tests\Services\OE\OERestClientTests.cs:line 178, 
    StatusCode=0, message='test', requestId='535345' 

означает, что пользовательские поля написаны в конце (потенциально долго) описание исключения. С другой стороны, я хочу, чтобы тип исключения был первой информацией, записанной в описании.

ОБНОВЛЕНИЕ 2: Я реализовал решение для этого, ищите мой собственный ответ ниже.

+0

Я ищу то же самое, я хочу добавить дополнительную информацию снаружи, а не в поле «Сообщение», но я хочу, чтобы формат ToString сохранялся со всей трассировкой стека и внутренними исключениями на нем. Было бы интересно увидеть код Exception.ToString() и скопировать его, добавив больше информации. – pauloya

+0

Ну, код охватывает большинство вещей, о которых вы упомянули. Хотя позже я вспомнил, что я мог использовать словарь Exception.Data для хранения моих настраиваемых материалов. Я предполагаю, что в этом случае это будет реализовано по умолчанию для ToString(), но я еще не пробовал. –

ответ

10

ОК, это то, что я придумал. Я реализовал класс расширения, который повторяет оригинальный механизм для форматирования исключения, но с изюминкой: пользовательское действие делегат, который предоставляет плагин для форматирования пользовательских полей:

public static class ExceptionFormatterExtensions 
{ 
    public static string ExceptionToString (
     this Exception ex, 
     Action<StringBuilder> customFieldsFormatterAction) 
    { 
     StringBuilder description = new StringBuilder(); 
     description.AppendFormat("{0}: {1}", ex.GetType().Name, ex.Message); 

     if (customFieldsFormatterAction != null) 
      customFieldsFormatterAction(description); 

     if (ex.InnerException != null) 
     { 
      description.AppendFormat(" ---> {0}", ex.InnerException); 
      description.AppendFormat(
       "{0} --- End of inner exception stack trace ---{0}", 
       Environment.NewLine); 
     } 

     description.Append(ex.StackTrace); 

     return description.ToString(); 
    } 
} 

Теперь вы можете использовать этот метод ваши собственные реализации ToString() без дублирования кода форматирования:

public override string ToString() 
    { 
     return this.ExceptionToString(
      description => 
      { 
       description.AppendFormat(
        ", HttpStatusCode={0}, RequestId='{1}'", 
        httpStatusCode, 
        RequestId); 
      }); 
    } 
12

Вы можете вручную добавить данные по умолчанию в строку, возвращаемую ToString, просмотрев свойства исключений. Например, следующий будет имитировать данные, возвращаемые по умолчанию, ToString методом создается исключение (при условии, нет внутренних исключений):

string.Format("{0}: {1}\r\n{2}", this.GetType().Name, this.Message, this.StackTrace); 

Или, вы можете просто добавить (или перед именем) данные, возвращаемые base.ToString к информацию, которую вы хотите добавить.

+1

Это, кажется, самое близкое решение того, что я имел в виду. Хотя вы забыли написать InnerException;) –

1

Внутри base.ToString переопределения вызова() и изменить результирующую строку к вашим потребностям ...

10

Вы можете переопределить метод ToString(), чтобы включить свою собственную информацию, и до сих пор называете базовое по умолчанию исключения, ToString(), как это:

public class MyException : Exception 
{ 
    public string CustomField { get; set; } 
    public override string ToString() 
    { 
     return CustomField + Environment.NewLine + base.ToString(); 
    } 
} 
4

Если вы в первую очередь смотрите на них в отладчике, то вы можете использовать атрибут [DebuggerDisplay] указать их форматирование и не трогать существующий ToString метода.

В противном случае, просто перегрузить ToString и обязательно назвать базовый класс версии base.ToString()

+1

Хотя не то, что я искал, +1 для упоминания об этом. –

18

Это все излишество. Ваше исключение должно просто переопределить свойство сообщения.

public override String Message { 
    get { 
     return base.Message + String.Format(", HttpStatusCode={0}, RequestId='{1}'", 
        httpStatusCode, 
        RequestId); 
    } 
} 

метод ToString по умолчанию для класса Exception в основном "ClassName: Message --> InnerException.ToString() StackTrace". Поэтому переопределение сообщения помещает текст вашего сообщения точно там, где оно должно быть.

+0

Это работает, если вы не идете по этой дороге, чтобы ввести пользовательскую трассировку стека. – yoyo

+0

@yoyo, да, но это не было требованием OP – Daryl

+0

Полностью верно, и ваш ответ хороший. (Я пришел сюда, чтобы найти что-то совсем другое.) – yoyo

Смежные вопросы