С#: переопределение метода ToString() для пользовательских исключений
У меня есть специальный класс исключений, который содержит некоторые дополнительные поля. Я хочу, чтобы они были записаны в методе ToString()
, но если я реализую свой собственный ToString()
, я теряю некоторые другие полезные вещи (например, записывая имя типа исключения, внутренние данные исключения и трассировку стека).
Каков наилучший способ/шаблон для реализации собственного метода ToString()
для таких исключений? В идеале он должен повторно использовать существующий механизм, но быть отформатирован таким же образом, как и стандартная реализация ToString()
.
UPDATE: добавление или добавление моих настраиваемых полей в base.ToString() текст не является идеальным IMHO, например
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: я применил для этого решение, найдите свой ответ ниже.
Ответы
Ответ 1
Хорошо, вот что я придумал. Я реализовал класс расширения, который реплицирует исходный механизм форматирования исключений, но с твист: пользовательский делегат Action, который предоставляет плагин для форматирования настраиваемых полей:
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);
});
}
Ответ 2
Это все излишество. Ваше исключение должно просто переопределить свойство сообщения.
public override String Message {
get {
return base.Message + String.Format(", HttpStatusCode={0}, RequestId='{1}'",
httpStatusCode,
RequestId);
}
}
Метод ToString по умолчанию для класса Exception в основном "ClassName: Message --> InnerException.ToString() StackTrace
". Поэтому переопределение сообщения помещает текст вашего сообщения точно там, где оно должно быть.
Ответ 3
Вы можете вручную добавить данные по умолчанию в строку, возвращаемую ToString
, просмотрев свойства исключений. Например, следующее будет имитировать данные, возвращаемые по умолчанию методом исключений ToString
(при условии отсутствия внутренних исключений):
string.Format("{0}: {1}\r\n{2}", this.GetType().Name, this.Message, this.StackTrace);
Или вы можете просто добавить (или добавить) данные, возвращаемые base.ToString
, к информации, которую вы хотите добавить.
Ответ 4
Вы можете переопределить метод ToString(), чтобы включить свою собственную пользовательскую информацию, и по-прежнему вызывать базовую версию Exception ToString() по умолчанию:
public class MyException : Exception
{
public string CustomField { get; set; }
public override string ToString()
{
return CustomField + Environment.NewLine + base.ToString();
}
}
Ответ 5
Если вы в основном смотрите на них в отладчике, вы можете использовать атрибут [DebuggerDisplay]
, чтобы указать их форматирование и не касаться существующего метода ToString
.
В противном случае просто перегрузите ToString
и обязательно вызовите версию базового класса base.ToString()
Ответ 6
Внутри переопределить вызов base.ToString() и изменить результирующую строку на ваши нужды...