Действительно, мало смысла возвращать вам Type.FullName
, но было бы еще меньше пользы, если бы возвращалась пустая строка или ноль. Вы спрашиваете, почему он существует. На этот вопрос не так-то просто ответить, и он является предметом многочисленных дискуссий в течение многих лет. Более десяти лет назад несколько новых языков решили, что было бы удобно неявно приводить объект к строке, когда это необходимо. К таким языкам относятся Perl, PHP и JavaScript, но ни один из них не следует полностью парадигме объектной ориентации.
подходы
Разработчики объектно-ориентированных языков столкнулись с более сложной проблемой. В общем, было три подхода для получения строкового представления объекта:
- Используйте множественное наследование, просто наследуйте от
String
, и вы можете быть преобразованы в строку
- Одиночное наследование: добавьте
ToString
в базовый класс как виртуальный метод
- Либо: сделать оператор приведения или конструктор копирования перегружаемым для строк
Возможно, вы спросите себя, зачем вам нужен ToString
или аналогичный. в первую очередь? Как уже отмечали некоторые другие: ToString
необходим для самоанализа (он вызывается, когда вы наводите указатель мыши на любой экземпляр объекта), и отладчик тоже его покажет. Как программист, вы знаете, что для любого ненулевого объекта вы всегда можете безопасно вызвать ToString
. Не нужен литой, не нужна конверсия.
Считается хорошей практикой программирования всегда реализовывать ToString
в ваших собственных объектах со значимым значением из ваших сохраняемых свойств. Перегрузки могут помочь, если вам нужны разные типы представления вашего класса.
Больше истории
Если вы углубитесь в историю, мы увидим, что SmallTalk использует более широкий подход. Базовый объект имеет гораздо больше методов, включая printString
, printOn
и т.д.
Небольшое десятилетие спустя, когда Бертран Мейер написал свою знаменательную книгу «Конструкция объектно-ориентированного программного обеспечения», он предложил использовать довольно широкий базовый класс GENERAL
. Он включает такие методы, как print
, print_line
и tagged_out
, причем последний показывает все свойства объекта, но не ToString
по умолчанию. Но он предполагает, что "второй базовый объект ANY, от которого происходят все пользовательские объекты, может быть расширен", что похоже на подход прототипа, который мы теперь знаем из JavaScript.
В C++, единственном языке множественного наследования, все еще широко используемом, не существует общего предка для всех классов. Это может быть лучший язык-кандидат для использования вашего собственного подхода, то есть используйте IStringable
. Но у C++ есть и другие способы: вы можете перегрузить оператор приведения и конструктор копирования, чтобы реализовать возможность строк. На практике необходимость явно указывать реализацию to-string (как вы предлагаете с IStringable
) становится довольно громоздкой. Программисты на С++ это знают.
В Java мы находим первое появление toString
для основного языка. К сожалению, в Java есть два основных типа: объекты и типы значений. Типы значений не имеют метода toString
, вместо этого вам нужно использовать Integer.toString
или привести к аналогу объекта. Это оказалось очень громоздким на протяжении многих лет, но программисты Java (включая меня) научились с этим жить.
Затем появился C# (я пропустил несколько языков, не хочу делать его слишком длинным), который изначально задумывался как язык отображения для платформы .NET, но оказался очень популярным после первоначального скептицизма. Разработчики C# (Андерс Хейлсберг и др.) смотрели в основном на C++ и Java и пытались взять лучшее из обоих миров. Тип значения остался, но был введен бокс. Это позволило неявно наследовать типы значений от Object. Добавление ToString
аналога Java было всего лишь небольшим шагом и было сделано для облегчения перехода от мира Java, но к настоящему времени оно показало свои неоценимые достоинства.
странность
Хотя вы прямо не спрашиваете об этом, но почему следующее должно потерпеть неудачу?
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 частью методов расширения для предотвращения ненужных исключений NullPointerException? Некоторые считают этот дизайн плохим, другие считают его экономией времени.
У Eiffel в то время был специальный класс NIL
, который представлял ничто, но все же имел все методы базового класса. Иногда мне хотелось, чтобы C# или Java вообще отказались от null, как это сделал Бертран Мейер.
Вывод
Широкий подход классических языков, таких как Eiffel и Smalltalk, был заменен очень узким подходом. В Java по-прежнему много методов для Object, а в C# — всего несколько. Это, конечно, хорошо для реализации. Хранение ToString
в пакете просто делает программирование чистым и в то же время понятным, а поскольку это virtual
, вы можете (и должны!) всегда переопределять его, что сделает ваш код более понятным.
-- Абель --
EDIT: автор вопроса отредактировал вопрос и сравнил его с IComparable
, то же самое, вероятно, верно и для ICloneable
. Это очень хорошее замечание, и часто считается, что IComparable
следовало бы включить в Object
. В соответствии с Java, C# имеет Equals, а не IComparable
, но в отличие от Java C# не имеет 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()
, оператор ??
) созданы для удобства. Ничего из этого не является необходимостью, но мы, конечно же, рады, что они у нас есть. Только когда мы знаем, как их правильно использовать, мы также находим истинную ценность функции (или нет).
person
Abel
schedule
13.10.2009
ToString()
, вы также должны спросить, почему существуетGetType()
, у нас уже есть операторtypeof
. И почему существуетEqual()
, у нас уже есть оператор==
. Были очень внятные причины для наличия ToString (и других) в базе: раньше или позже нужно отображать так или иначе. Таким образом, каждому объекту просто требуетсяToString()
. В качестве бонуса: вы всегда можете создатьIStringable
и использовать его вместо него! А, кстати, зачем вообще существует C#? - person Abel   schedule 14.10.2009object
; что плохого в том, чтобы вводить имя объекта и иметь расширяемый список свойств? Гипотетически Visual Studio (не C#) можно было бы запрограммировать на показ значений свойств/переменных встроенных типов, таких какstring
иint
, из коробки, а пользовательские типы просто должны были бы полагаться наDebuggerDisplayAttribute
(хотя да, атрибут display не был с момента появления .NET). - person jrh   schedule 10.01.2018