Почему/когда было бы целесообразно переопределить ToString?

Я изучаю С#, и мне интересно, что может означать и преимущество переопределения ToString, как показано в примере ниже.

Можно ли это сделать более простым способом, используя общий метод без переопределения?

public string GetToStringItemsHeadings
{
    get { return string.Format("{0,-20} {1, -20}", "Office Email", "Private Email"); }
}


public override string ToString()
{
    string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal);
    return strOut;
}

Ответ 1

  • Вам нужно переопределить ToString? Нет.

  • Можете ли вы получить строковое представление своего объекта по-другому? Да.

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

Конкретно,

Console.WriteLine(yourObject);

будет вызывать yourObject.ToString().

Ответ 2

Я просто дам вам ответ прямо из Framework Design Guidelines из серии .NET Development.

ИЗБЕГАЙТЕ исключение из ToString

CONSIDER возвращает уникальную строку, связанную с экземпляром.

CONSIDER, имеющий выход ToString, является допустимым вводом для любых методов синтаксического анализа этого типа.

DO убедитесь, что ToString не имеет видимых побочных эффектов.

DO сообщите конфиденциальную информацию с помощью переопределения ToString только после запроса соответствующего разрешения. Если запрос разрешения не выполняется, верните строку, исключая конфиденциальную информацию.

Метод Object.ToString предназначен для общего отображения и отладки. Реализация по умолчанию просто предоставляет имя типа объекта. Реализация по умолчанию не очень полезна, и рекомендуется, чтобы метод был переопределен.

DO переопределяет ToString, когда может быть возвращена интересная удобочитаемая строка. Реализация по умолчанию не очень полезна, и пользовательская реализация может почти всегда обеспечивать большую ценность.

DO предпочитают дружественное имя по уникальному, но не читаемому идентификатору.

Также стоит упомянуть, что Chris Sells также объясняет в руководствах, что ToString часто опасен для пользовательских интерфейсов. Как правило, мое эмпирическое правило заключается в том, чтобы выставить свойство, которое будет использоваться для привязки информации к пользовательскому интерфейсу, и оставить переопределение ToString для отображения диагностической информации разработчику. Вы также можете украсить свой тип с помощью DebuggerDisplayAttribute.

DO попытайтесь сохранить строку, возвращенную с ToString короткой. Отладчик использует ToString для получения текстового представления объекта, который будет показан разработчику. Если строка длиннее, чем может отображать отладчик, процесс отладки затруднен.

DO форматирование строк на основе текущей культуры потоков при возврате информации, зависящей от культуры.

DO обеспечивают перегрузку ToString(string format) или реализуют IFormattable, если строка возвращает из ToString чувствительна к культуре или существуют различные способы форматирования строки. Например, DateTime обеспечивает перегрузку и реализует IFormattable.

НЕ НЕ возвращает пустую строку или null из ToString

Клянусь этими рекомендациями, и вы должны это сделать. Я не могу сказать вам, как мой код улучшился именно с помощью этой рекомендации для ToString. То же самое касается таких вещей, как IEquatable(Of T) и IComparable(Of T). Эти вещи делают ваш код очень функциональным, и вы не пожалеете о том, что потребуется дополнительное время для реализации любого из них.

Лично я никогда не использовал ToString для пользовательских интерфейсов, я всегда показывал свойство или метод некоторого рода. В большинстве случаев вы должны использовать ToString для целей отладки и разработки. Используйте его для отображения важной диагностической информации.

Ответ 3

Переопределение ToString() позволяет вам дать полезное понятное для строки представление класса.

Это означает, что вывод может отображать полезную информацию о вашем классе. Например, если у вас есть класс Person, вы можете выбрать ToString() вывод идентификатора лица, его имя, его имя и т.д. Это очень полезно при отладке или протоколировании.

Что касается вашего примера - трудно сказать, полезно ли ваше переопределение, не зная, что этот класс, но сама реализация в порядке.

Ответ 4

Это всегда уместно, но внимательно рассмотрите намерения, стоящие за тем, что вы показываете

Лучший вопрос: спросить:

Почему нужно переопределить ToString()?

ToString() - это окно в состояние объекта. Акцент на состоянии как требование. Сильные языки ООП, такие как Java/С#, злоупотребляют моделью ООП, инкапсулируя все в классе. Представьте, что вы кодируете язык, который не соответствует сильной модели ООП; подумайте, используете ли вы класс или функцию. Если вы будете использовать его как функцию (т.е. Глагол, действие), а внутреннее состояние временно сохраняется между вводом/выводом, ToString() не добавит значения.

Как и многие другие, важно рассмотреть то, что вы выводите с помощью ToString(), поскольку оно может использоваться отладчиком или другими системами.

Мне нравится представлять метод ToString в качестве параметра -help объекта. Он должен быть коротким, читаемым, очевидным и легко отображаемым. Он должен отображать то, что объект не то, что он делает. Учитывая все это, подумайте...

Использовать пример - анализ TCP-пакета:

Не сетевой захват на уровне приложений, а что-то с большим количеством мяса, как захват pcap.

Вы хотите перегрузить ToString() только для уровня TCP, чтобы вы могли печатать данные на консоли. Что это будет включать? Вы можете сойти с ума и разобрать все данные TCP (т.е. TCP является сложным)...

Что включает в себя:

  • Исходный порт
  • Порт назначения
  • Последовательный номер
  • Номер подтверждения
  • Смещение данных
  • Флаги
  • Смещение окна
  • Контрольная сумма
  • Срочный указатель
  • Параметры (я даже не собираюсь туда идти)

Но хотите ли вы получить весь этот мусор, если вы вызываете TCP.ToString() на 100 пакетов? Конечно, нет, это будет информационная перегрузка. Легкий и очевидный выбор также самый разумный...

Представьте, что люди ожидали увидеть:

  • Исходный порт
  • Порт назначения

Я предпочитаю разумный вывод, который легко для людей разобрать, но YMMV.

TCP:[destination:000, source:000]

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

Но как насчет всей остальной части той сочной информации, о которой я говорил раньше, не так уж и полезно? Я доберусь до этого, но сначала...


ToString() один из самых ценных и недоиспользуемых методов всего времени

По двум причинам:

  • Люди не понимают, что такое ToString() для
  • В базовом классе "Объект" отсутствует другой, не менее важный, строковый метод.

Причина 1 - Не злоупотребляйте полезностью ToString():

Многие люди используют ToString(), чтобы вытащить простое строковое представление объекта. В руководстве С# указано состояние:

ToString является основным методом форматирования в .NET Framework. Он преобразует объект в его строковое представление, так что он подходит для отображения.

Дисплей, не обрабатывается. Это не значит, возьмите мое красивое строковое представление TCP-пакета выше и потяните исходный порт с помощью regex:: cringe::.

Правильный способ сделать это - вызвать ToString() непосредственно в свойстве SourcePort (что BTW является пользователем, поэтому ToString() уже должен быть доступен).

Если вам нужно что-то более надежное, чтобы упаковать состояние сложного объекта для машинного разбора, вам будет лучше использовать стратегию структурированной сериализации.

К счастью, такие стратегии очень распространены:

  • ISerializable (С#)
  • Pickle (Python)
  • JSON (Javascript или любой язык, который его реализует)
  • SOAP
  • и т.д...

Примечание. Если вы не используете PHP, потому что, herp-derp, есть функция для этого:: snicker::

Причина 2 - ToString() недостаточно:

Мне еще предстоит увидеть язык, который реализует это в ядре, но я видел и использовал вариации этого подхода в дикой природе.

Некоторые из них включают:

  • ToVerboseString()
  • ToString (многословным = истина)

В принципе, этот волосатый беспорядок в состоянии TCP-пакета должен быть описан для удобства чтения. Чтобы избежать "избиения мертвой лошади", говорящей о TCP, я "укажу пальцем" на случай №1, где я думаю, что ToString() и ToVerboseString() недостаточно используются...

Использовать массив - Массивы:

Если вы в основном используете один язык, вам, вероятно, нравится этот языковой подход. Для таких людей, как я, которые прыгают между разными языками, количество различных подходов может раздражать.

Т.е. количество раз, которое это раздражало меня, больше, чем сумма всех пальцев каждого индуистского бога в сочетании.

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

То, что я прошу, - очень простой подход:

print(array.ToString());

Выходы: 'Массив [x]' или 'Массив [x] [y]'

Где x - количество элементов в первом измерении, а y - количество элементов во втором измерении или какое-то значение, указывающее на то, что второе измерение является зазубренным (min/max range может быть?).

и

print(array.ToVerboseString());

Выводит весь текст в хорошенькой печати, потому что я ценю красивые вещи.

Надеюсь, это проливает некоторый свет на тему, которая раздражает меня в течение длительного времени. По крайней мере, я посыпал небольшую приманку для троллей для PHPers, чтобы снизить этот ответ.

Ответ 5

Это о хорошей практике, как и все, действительно.

ToString() используется во многих местах для возврата строкового представления объекта, обычно для потребления человеком. Часто эта же строка может использоваться для регидратации объекта (например, int или DateTime), но это не всегда заданное (например, дерево может иметь полезное строковое представление, которое просто отображает граф, но ясно, что вы не можете использовать это, чтобы перестроить его).

В частности, отладчик будет использовать это для отображения переменной в окнах просмотра, мгновенных окнах и т.д., поэтому ToString действительно неоценим для отладки.

В общем случае такой тип часто имеет явный член, который также возвращает строку. Например, пара Lat/Long может иметь ToDecimalDegrees, которая возвращает, например, "-10, 50", но также может иметь ToDegreesMinutesSeconds, поскольку это другой формат пары Lat/Long. Тот же тип может также переопределить ToString с одним из тех, которые предоставляют "по умолчанию" для таких вещей, как отладка или даже для таких вещей, как рендеринг веб-страниц (например, конструкция @ в Razor записывает ToString() результат нестрочного выражения в выходной поток).

Ответ 6

object.ToString() преобразует объект в его строковое представление. Если вы хотите изменить то, что возвращается, когда пользователь вызывает ToString() в созданном вами классе, вам необходимо переопределить ToString() в этом классе.

Ответ 7

Если вы не переопределите ToString, вы получите реализацию базовых классов, которая для Object - это просто краткое имя класса.

Если вам нужна другая, более значимая или полезная реализация ToString, то переопределите ее.


Это может быть полезно при использовании списка вашего типа в качестве источника данных для ListBox по мере того, как будет отображаться ToString.

Другое сидение происходит, когда вы хотите передать свой тип String.Format, который вызывает ToString, чтобы получить представление вашего типа.

Ответ 8

Хотя я думаю, что самая полезная информация уже предоставлена, я добавлю свои два цента:

  • ToString() предназначен для переопределения. Его реализация по умолчанию возвращает имя типа, которое, хотя может быть полезно иногда (особенно при работе с большим количеством объектов), не хватает в большинстве случаев.

  • Помните, что для целей отладки вы можете положиться на DebuggerDisplayAttribute. Вы можете прочитать об этом здесь.

  • Как правило, в POCOs вы всегда можете переопределить ToString(). POCOs представляют собой структурированное представление данных, которое обычно может стать строкой.

  • Design ToString - текстовое представление вашего объекта. Возможно, его основные поля и данные, возможно, описание количества элементов в коллекции и т.д.

  • Всегда старайтесь вставлять эту строку в одну строку и иметь только важную информацию. Если у вас есть класс Person с именем, адресом, номером и т.д., Возвращайте только основные данные (укажите номер ID).

  • Будьте осторожны, чтобы не переопределить хорошую реализацию ToString(). Некоторые классы классов уже реализуют ToString(). Переопределение этой реализации по умолчанию - это плохо: люди будут ожидать определенный результат от ToString() и получить другой.

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

Ответ 9

Кое-что еще никто не упомянул: переопределяя ToString(), вы также можете рассмотреть возможность переопределения ToString(string Formatter), чтобы вы могли сделать следующее:

 public override ToString() {
   string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal);
   return strOut;
 }

 public override ToString(string formatter) {
   string strOut = this.ToString();
   switch (formatter.ToLower()) {
     case "w":
       strOut = m_Work;
       break;
     case "p":
       strOut = m_Personal;
       break;
     case "hw":
       strOut = string.Format("mailto:{0}", m_Work);
       break;
   }
   return strOut;
}

Что может быть полезно.

Ответ 10

Одним из преимуществ переопределения ToString() является поддержка инструментальной поддержки Resharper: Alt + Ins → "Форматирование элементов" и он записывает ToString() для вас.

Ответ 11

В некоторых случаях упрощается чтение значений пользовательских классов в окне просмотра отладчика. Если я точно знаю, что хочу видеть в окне просмотра, когда я переопределяю ToString с этой информацией, я вижу это.

Ответ 12

При определении структур (фактически пользовательских примитивов) я считаю хорошей практикой иметь методы ToString и Parse и TryParse, особенно для сериализации XML. В этом случае вы преобразуете все состояние в строку, чтобы его можно было прочитать позже.

Классы, однако, представляют собой более сложные структуры, которые обычно будут слишком сложными для использования ToString и Parse. Их методы ToString, а не сохранение всего состояния, могут быть простым описанием, которое поможет вам определить их состояние, например уникальный идентификатор, например имя или идентификатор, или, может быть, количество для списка.

Кроме того, как сказал Робби, переопределение ToString позволяет вызывать ToString в качестве базового типа типа object.

Ответ 13

Вы можете использовать это, когда у вас есть объект с неинтуитивным значением строкового представления, например, человека. Поэтому, если вам нужно, например, напечатать этого человека, вы можете использовать это переопределение для подготовки его формата.

Ответ 14

Метод Object.ToString должен использоваться только для целей отладки. Реализация по умолчанию показывает имя типа объекта, которое не очень полезно. Подумайте о том, чтобы переопределить этот метод, чтобы обеспечить лучшую информацию для диагностики и отладки. Пожалуйста, учтите, что в инфраструктурах регистрации часто используется метод ToString, поэтому вы найдете эти текстовые фрагменты в файлах журналов.

Не возвращать локализованные текстовые ресурсы в методе Object.ToString. Причина в том, что метод ToString всегда должен возвращать то, что разработчик может понять. Разработчик может не говорить на всех языках, поддерживаемых приложением.

Внедрить интерфейс IFormattable, если вы хотите вернуть удобный для пользователя локализованный текст. Этот интерфейс определяет перегрузку ToString с параметрами format и formatProvider. ФорматProvider помогает вам форматировать текст в знании культуры.

Смотрите также: Object.ToString и IFormattable

Ответ 15

Упрощение зависит от того, как будет использоваться ваше свойство. Если вам просто нужно форматировать строку один раз, то это не делает так много смысла, переопределяя ее.

Однако, похоже, что вы переопределяете метод ToString, чтобы не возвращать нормальные строковые данные для вашего свойства, а для выполнения стандартного шаблона форматирования. Поскольку вы используете string.format с дополнением.

Поскольку вы сказали, что вы учитесь, это упражнение также затрагивает основные принципы объектно-ориентированного программирования, связанные с инкапсуляцией и повторным использованием кода.

string.format, принимающий аргументы, которые вы установили для заполнения, гарантирует, что свойство будет отформатировано одинаково каждый раз для любого кода, который его вызывает. Кроме того, в будущем вам нужно изменить его только в одном месте, а не во многих.

Отличный вопрос, а также отличные ответы!

Ответ 16

Мне полезно переопределить метод ToString для классов сущностей, поскольку он помогает быстро выявлять проблемы при тестировании, особенно когда утверждение не выполняется, тестовая консоль будет вызывать метод ToString для объекта.

Но в согласии с тем, что было сказано ранее, чтобы дать читаемое человеком представление объекта, о котором идет речь.