Есть ли способ автоматически переопределить ToString() в классе?
Мне полезно переопределить ToString() на многих простых классах DTO/POCO, которые я пишу, чтобы показать хорошую информацию при зависании экземпляров в отладчике.
Вот один пример:
public class IdValue< T >
{
public IdValue( int id, T value )
{
Id = id;
Value = value;
}
public int Id { get; private set; }
public T Value { get; private set; }
public override string ToString()
{
return string.Format( "Id: {0} Value: {1}", Id, Value );
}
}
Есть ли способ в .NET для автоматического переопределения ToString(), в котором перечислены общедоступные свойства или есть хорошее соглашение?
Ответы
Ответ 1
Вы можете переопределить ToString в базовом классе, а затем использовать отражение в экземпляре, чтобы открыть общедоступные свойства производного класса. Но это, скорее всего, приведет к проблемам производительности в других областях вашего кода. Кроме того, поскольку ToString используется многими вещами (String.Format, привязка данных по умолчанию и т.д.), Переопределение ToString для целей отладки сделает ваши классы менее полезными в других сценариях.
Вместо этого вы можете использовать атрибут DebuggerDisplay, чтобы контролировать, как отладчик показывает подсказки и информацию о зависании в окне просмотра и т.д. Я уверен, что это работает, если вы примените его к базовому классу. Вы также можете создавать персонализированные визуализаторы, но более активно. Ознакомьтесь с этой ссылкой для получения дополнительной информации об улучшении работы дисплея отладки.
Улучшение отладки
Ответ 2
Вы можете использовать JSON:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
namespace ConsoleApplication1
{
public class IdValue<T>
{
public IdValue(int id, T value)
{
Id = id;
Value = value;
}
public int Id { get; private set; }
public T Value { get; private set; }
public override string ToString()
{
return new JavaScriptSerializer().Serialize(this);
}
}
class Program
{
static void Main(string[] args)
{
var idValue = new IdValue<string>(1, "Test");
Console.WriteLine(idValue);
Console.ReadKey();
}
}
}
Что дает этот вывод:
{ "Идентификатор": 1, "Значение": "Тест" }
Ответ 3
Это не очень хороший дизайн. Я бы посоветовал вам извлекать значения, когда вам нужно их регистрировать или иметь вспомогательный метод (вы можете использовать методы расширения в System.Object).
Ответ 4
здесь Способ, которым это МОЖЕТ быть сделано в дружественном отладчике способом
public override string ToString()
{
stringBuilder sb = ... your usual string output
AppendDebug(sb);
return sb.Tostring();
}
[Conditional("DEBUG")]
private void AppendDebug(stringBuilder sb)
{
sb.Append( ... debug - specific info )
}
Атрибут [Условный] является ключом к вашему вопросу.
Ответ 5
Слушайте людей, которые предупреждают вас о производительности и/или соображениях дизайна. Вы сильно привязываете поведение, чтобы удовлетворить довольно ограниченную потребность, когда вы можете отделить свои потребности, используя расширение или декоратор.
Ответ 6
Если вы не возражаете против внешней зависимости, вы можете обратиться к структуре, помогающей распечатать все свойства ваших объектов, например StatePrinter
Пример использования
class AClassWithToString
{
string B = "hello";
int[] C = {5,4,3,2,1};
// Nice stuff ahead!
static readonly StatePrinter printer = new StatePrinter();
public override string ToString()
{
return printer.PrintObject(this);
}
}