Есть ли способ автоматически переопределить 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);
  }
}