Почему существует объект object.ToString()?

Не намного ли более элегантный и опрятный интерфейс IStringable?

Кому нужен этот Type.FullName объект, возвращенный нам?

РЕДАКТИРОВАТЬ: все спрашивают, почему я думаю, что это более элегантно..

Ну, именно так, вместо объекта IComparable, объект имел бы метод CompareTo, который по умолчанию генерирует исключение или возвращает 0.

Есть объекты, которые нельзя и не должны описывать как строку. объект мог бы в равной степени возвратить string.Empty. Type.FullName является просто произвольным выбором.

И для таких методов, как Console.Write(object), я думаю, что это должно быть: Write (IStringable).

Однако, если вы используете WriteLine для чего-либо, кроме строк (или что-то, что его ToString очевидно, например числа), мне кажется, что это только для режима отладки.

Кстати, как я должен комментировать вас всех? Это нормально, что я отправляю ответ?

Ответ 1

Существует три виртуальных метода, которые IMHO никогда не добавляли в System.Object...

  • ToString()
  • GetHashCode()
  • Равно()

Все это могло быть реализовано, как вы предлагаете, с помощью интерфейса. Если бы они сделали это, я думаю, нам будет намного лучше. Так почему же это проблема? Давайте просто сосредоточимся на ToString():

  • Если ToString() предполагается реализовать кем-то, использующим ToString() и отображая результаты, у вас есть неявный контракт, который компилятор не может обеспечить. Вы предполагаете, что ToString() перегружен, но нет способа заставить это быть.
  • С помощью IStringable вам нужно будет добавить это только к своему универсальному типу ограничений или получить от него интерфейс, чтобы потребовать его использования при реализации объектов.
  • Если вы используете перегрузку ToString() для отладчика, вы должны начать использовать [System.Diagnostics.DebuggerDisplayAttribute].
  • Что касается этой реализации для преобразования объектов в строки через String.Format() и/или Console.WriteLine, они могли бы отложить до объекта System.Convert.ToString(объект) и проверить на что-то вроде "IStringable", не выполнив имя типа, если оно не реализовано.
  • Как указывает Кристофер Эстеп, эта культура специфична.

Итак, я думаю, я остаюсь здесь один, говоря, что я ненавижу System.Object и все его виртуальные методы. Но я люблю С# в целом, и в целом я думаю, что дизайнеры отлично поработали.

Примечание. Если вы намерены зависеть от того, что поведение ToString() перегружено, я предлагаю вам продолжить и определить свой интерфейс IStringable. К сожалению, вам придется выбрать другое имя для метода, если вы действительно хотите его потребовать.

более

Мои коллеги и я просто говорили по этой теме. Я думаю, что еще одна большая проблема с ToString() отвечает на вопрос "для чего он используется?". Отображается ли текст? Текст сериализации? Отладка текста? Полное имя типа?

Ответ 2

Наличие Object.ToString позволяет использовать API, например Console.WriteLine.

С точки зрения дизайна дизайнеры BCL считают, что возможность предоставления строкового представления экземпляра должна быть общей для всех объектов. Истинное полное имя типа не всегда полезно, но они чувствовали, что способность настраивать представление на корневом уровне перевешивает незначительную досаду, когда видят полное имя типа в выводе.

Правда, вы можете реализовать Console.WriteLine без Object.ToString и вместо этого выполнить проверку интерфейса и по умолчанию указать полное имя типа, если интерфейс не присутствовал. Но тогда каждый API, который хотел бы получить строковое представление экземпляра объекта, должен был бы реализовать эту логику. Учитывая количество раз, когда Object.ToString используется только внутри основного BCL, это привело бы к многому дублированию.

Ответ 3

Я предполагаю, что это существует, потому что это невероятно удобная вещь для всех объектов и не требует использования add'l cruft. Почему, по-вашему, IStringable будет более элегантным?

Ответ 4

Совсем нет.

Он не нуждается в реализации и, он возвращает результаты, специфичные для конкретной культуры.

Этот метод возвращает читаемую человеком строку, чувствительную к культуре. Например, для экземпляра класса Double, значение которого равно нулю, реализация Double..::. ToString может возвращать "0.00" или "0,00" в зависимости от текущей культуры пользовательского интерфейса.

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

Ответ 5

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

Ответ 6

Mmmm, поэтому он может быть переопределен в производных классах?

Ответ 7

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

Ответ 8

С помощью IStringable вам нужно будет выполнить дополнительную проверку/бросок, чтобы увидеть, можно ли вывести объект в строчном формате. Это слишком большой удар по перфомансу для такой общей операции, которая должна быть хорошей вещью для 99,99% всех объектов в любом случае.

Ответ 9

Структуры и объекты имеют элемент ToString(), чтобы облегчить отладку.

Самый простой пример этого можно увидеть с помощью Console.WriteLine, который получает полный список типов, включая объект, но также получает params object[] args. Поскольку Консоль часто является слоем поверх TextWriter, эти инструкции также полезны (иногда) при записи в файлы и другие потоки (сокеты).

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

Ответ 10

Мой новый базовый класс:

class Object : global::System.Object
{
    [Obsolete("Do not use ToString()", true)]
    public sealed override string ToString()
    {
        return base.ToString();
    }

    [Obsolete("Do not use Equals(object)", true)]
    public sealed override bool Equals(object obj)
    {
        return base.Equals(this, obj);
    }

    [Obsolete("Do not use GetHashCode()", true)]
    public sealed override int GetHashCode()
    {
        return base.GetHashCode();
    }
}

Ответ 11

На самом деле мало пользы от возврата Type.FullName, но было бы еще меньше использовать, если была возвращена пустая строка или null. Вы спрашиваете, почему он существует. Это не так просто ответить и много лет обсуждалось много. Более десятилетия назад несколько новых языков решили, что было бы удобно неявно отбрасывать объект в строку, когда это было необходимо, эти языки включают Perl, PHP и JavaScript, но ни одна из них не полностью соответствует парадигме объектной ориентации.

Подходы

У дизайнеров объектно-ориентированных языков была более сложная проблема. В общем, было три подхода для получения строкового представления объекта:

  • Используйте множественное наследование, просто наследуйте от String, и вы можете быть переведены в строку
  • Одиночное наследование: добавьте ToString в базовый класс как виртуальный метод
  • Либо: сделайте оператор броска или конструктор копирования перегруженным для строк

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

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

Дополнительная история

Если вы погружаетесь немного глубже в историю, мы видим, что SmallTalk использует более широкий подход. У базового объекта есть еще много методов, включая printString, printOn и т.д.

Небольшое десятилетие спустя, когда Бертран Мейер написал свою ориентировочную книгу "Объектно-ориентированное программное обеспечение", он предложил использовать довольно широкий базовый класс GENERAL. Он включает в себя такие методы, как print, print_line и tagged_out, последний показывает все свойства объекта, но не по умолчанию ToString. Но он предполагает, что "второй базовый объект ANY, к которому все пользовательские данные могут быть получены, может быть расширен", что похоже на прототипный подход, который мы теперь знаем из JavaScript.

В С++ единственный язык множественного наследования все еще широко используется, для всех классов не существует общего предка. Это может быть лучший язык кандидата для использования вашего собственного подхода, т.е. Использовать IStringable. Но С++ имеет другие способы: вы можете перегрузить оператор трансляции и конструктор копирования для реализации стробируемости. На практике необходимость в явном представлении о строковой реализации (как вы предлагаете с помощью IStringable) становится довольно громоздкой. Программисты на C++ знают это.

В Java мы обнаруживаем первое появление ToString для основного языка. К сожалению, Java имеет два основных типа: объекты и типы значений. Типы значений не имеют метода ToString, вместо этого вам нужно использовать Integer.toString или применить к объектной копии. Это оказалось очень громоздким на протяжении многих лет, но Java-программисты (включая меня) научились жить с ним.

Затем появился С# (я пропустил несколько языков, не хочу делать его слишком длинным), который сначала был предназначен как язык отображения для платформы .NET, но оказался очень популярен после первоначального скептицизма. Дизайнеры С# (Anders Hejlsberg и др.) Смотрели в основном на С++ и Java и старались использовать лучшее из обоих миров. Тип значения остался, но был введен бокс. Это позволило получить значения типов значений из Объекта неявно. Добавление ToString, аналогичное Java, было всего лишь небольшим шагом и было сделано для облегчения перехода от Java-мира, но пока показало его неоценимые достоинства.

Oddity

Хотя вы прямо не спрашиваете об этом, но почему это должно произойти:

object o = null;
Console.WriteLine(o.ToString());

и пока вы думаете об этом, рассмотрите следующее, что не подведет:

public static string MakeString(this object o)
{ return o == null ? "null" : o.ToString();  }

// elsewhere:
object o = null;
Console.WriteLine(o.MakeString());

из-за чего я задаю вопрос: может, если бы разработчики языка заранее подумали о методах расширения, метод ToString будет частью методов расширения для предотвращения ненужных NullPointerExceptions? Некоторые считают этот плохой дизайн, другие считают его временным.

Эйфель в то время имел специальный класс NIL, который представлял собой небытие, но все же имел все методы базового класса. Иногда мне хотелось, чтобы С# или Java полностью отказались от нуля, как это сделал Бертран Мейер.

Заключение

Широкий подход классических языков, таких как Eiffel и Smalltalk, был заменен очень узким подходом. Java по-прежнему имеет множество методов для Object, С# имеет только несколько. Это, конечно, хорошо для реализаций. Сохранение ToString в пакете просто делает программирование чистым и понятным одновременно, а поскольку оно virtual, вы можете (и должны!) Всегда переопределять его, что сделает ваш код лучше воспринятым.

- Abel -

РЕДАКТИРОВАТЬ:, апеллятор отредактировал вопрос и сделал сравнение с IComparable, это, вероятно, верно для ICloneable. Это очень хорошие замечания, и часто считается, что IComparable должен был быть включен в Object. В соответствии с Java, С# имеет Equals, а не IComparable, но против Java, С# не имеет ICloneable (Java имеет clone()).

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

CarInfo car = new CarInfo();
BikeInfo bike = new BikeInfo();
string someInfoText = "Car " +
   (car is IStringable) ? ((IStringable) car).ToString() : "none") +
   ", Bike " + 
   (bike is IStringable) ? ((IStringable) bike).ToString() : "none");

и сравните это с этим. В зависимости от того, что вам будет легче, вы должны выбрать:

CarInfo car = new CarInfo();
BikeInfo bike = new BikeInfo();
string someInfoText = "Car " + car.ToString() + ", Bike " + bike.ToString();

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

Ответ 12

Я хотел бы добавить пару соображений о том, почему определение класса .NET System.Object имеет метод ToString() или функцию-член, в дополнение к предыдущим сообщениям при отладке.

Так как среда .NET Common Language Runtime (CLR) или Execution Runtime поддерживает Reflection, возможность создания экземпляра объекта, поскольку строковое представление типа класса кажется существенным и фундаментальным. И если я не ошибаюсь, все ссылочные значения в CLR выводятся из System.Object, имея метод ToString() в классе, который обеспечивает его доступность и использование через Reflection. Определение и реализация интерфейса по строкам IStringable не является обязательным или обязательным при определении класса в .NET и не обеспечит возможность динамического создания нового экземпляра после запроса сборки для поддерживаемых типов классов.

Поскольку более продвинутые функции .NET, доступные в версиях 2.0, 3.0 и 3.5, таких как Generics и LINQ, основаны на Reflection и динамическом создании экземпляров, не говоря уже о поддержке .NET Dynamic Language Runtime (DLR), которые позволяют .NET. реализация языков сценариев, таких как Ruby и Python, возможность идентифицировать и создавать экземпляр с помощью строкового типа представляется важной и незаменимой функцией во всех определениях классов.

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

Возможно, обзор статей и книг Джеффри Ричера и Дона Бокса по дизайну и архитектуре .NET Framework также может помочь лучше понять эту тему.