Сравнение
String.Format("Hello {0}", "World");
с
"Hello {0}".Format("World");
Почему дизайнеры .Net выбрали статический метод над методом экземпляра? Как вы думаете?
Сравнение
String.Format("Hello {0}", "World");
с
"Hello {0}".Format("World");
Почему дизайнеры .Net выбрали статический метод над методом экземпляра? Как вы думаете?
Я действительно не знаю ответа, но я подозреваю, что он имеет какое-то отношение к аспекту вызова методов в строковых литералах напрямую.
Если я правильно помню (я действительно не проверял это, потому что у меня нет старой среды IDE), ранние версии С# IDE имели проблемы с обнаружением вызовов методов против строковых литералов в IntelliSense, и это имеет большое влияние о возможности обнаружения API. Если это так, введите следующее, не окажет вам никакой помощи:
"{0}".Format(12);
Если вы были вынуждены ввести
new String("{0}").Format(12);
Было бы ясно, что не было никакого преимущества для того, чтобы метод Format использовал метод экземпляра, а не статический метод.
Библиотеки .NET были разработаны многими теми же людьми, которые дали нам MFC, и, в частности, класс String имеет сильное сходство с классом CString в MFC. У MFC есть метод форматирования экземпляра (который использует коды форматирования стиля печати, а не стиль фигурной скобки .NET), что является болезненным, потому что нет такой вещи, как литерал CString. Поэтому в кодовой базе MFC, над которой я работал, я вижу много всего:
CString csTemp = "";
csTemp.Format("Some string: %s", szFoo);
что является болезненным. (Я не говорю, что вышеприведенный код - отличный способ сделать что-то даже в MFC, но похоже, что большинство разработчиков проекта узнали, как использовать CString:: Format). Исходя из этого наследия, я могу представить, что дизайнеры API пытались избежать такой ситуации снова.
Поскольку метод Format не имеет ничего общего с текущим значением строки.
Это верно для всех строковых методов, потому что строки .NET неизменяемы.
Если он был нестационарным, для начала вам понадобится строка.
Это: строка формата.
Я считаю, что это всего лишь еще один пример многих недостатков дизайна на платформе .NET(и я не имею в виду это как пламя, я по-прежнему считаю, что платформа .NET превосходит большинство других фреймворков).
Ну, я думаю, вы должны быть довольно особенными в этом вопросе, но, как говорят люди, для String.Format имеет смысл быть статичным из-за подразумеваемой семантики. Рассмотрим:
"Hello {0}".Format("World"); // this makes it sound like Format *modifies*
// the string, which is not possible as
// strings are immutable.
string[] parts = "Hello World".Split(' '); // this however sounds right,
// because it implies that you
// split an existing string into
// two *new* strings.
Первое, что я сделал, когда мне нужно было перейти на VS2008 и С# 3, должно было это сделать
public static string F( this string format, params object[] args )
{
return String.Format(format, args);
}
Итак, теперь я могу изменить свой код из
String.Format("Hello {0}", Name);
к
"Hello {0}".F(Name);
который я предпочитал в то время. В настоящее время (2014 год) я не беспокоюсь, потому что это просто еще одна проблема, заключающаяся в повторном добавлении этого к каждому произвольному проекту, который я создаю, или ссылку в библиотеке некоторых пакетов.
Почему разработчики .NET выбрали его? Кто знает. Это кажется полностью субъективным. Мои деньги находятся на
На самом деле нет других веских причин, по которым я могу найти
Я думаю, что это потому, что Format не берет строку как таковую, а "строку формата". Большинство строк равны таким вещам, как "Bob Smith" или "1010 Main St", или что у вас есть, а не "Hello {0}", как правило, вы помещаете эти строки только в том случае, когда вы пытаетесь использовать шаблон для создания другого string, как метод factory, и поэтому он сам придает статическому методу.
Я думаю, это потому, что это метод создателя (не уверен, есть ли лучшее имя). Все, что он делает, это взять то, что вы ему даете, и вернуть один строковый объект. Он не работает с существующим объектом. Если он был нестационарным, для начала вам понадобится строка.
Поскольку метод Format не имеет ничего общего с текущим значением строки. Значение строки не используется. Он берет строку и возвращает ее.
Возможно, разработчики .NET сделали это так, потому что JAVA сделал это так...
Объятия и расширения.:)
Смотрите: http://discuss.techinterview.org/default.asp?joel.3.349728.40
Строки .NET неизменяемы
Поэтому наличие метода экземпляра абсолютно не имеет смысла.
В этой логике класс string не должен иметь методов экземпляра, которые возвращают измененные копии объекта, но у него много (Trim, ToUpper и т.д.). Кроме того, многие другие объекты в рамках делают это тоже.
Я согласен, что если они должны были сделать его методом экземпляра, Format
кажется, что это будет плохое имя, но это не значит, что функциональность не должна быть методом экземпляра.
Почему не это? Это согласуется с остальные .NET framework
"Hello {0}".ToString("Orion");
Методы экземпляра хороши, если у вас есть объект, который поддерживает какое-либо состояние; процесс форматирования строки не влияет на строку, в которой вы работаете (read: не изменяет ее состояние), она создает новую строку.
С помощью методов расширения вы можете теперь использовать свой торт и съесть его (т.е. вы можете использовать последний синтаксис, если он поможет вам лучше спать ночью).
Мне кажется, что лучше использовать String.Format, но я мог видеть, что нужно иметь нестационарную функцию, когда у вас уже есть строка, хранящаяся в переменной, которую вы хотите "форматировать".
В стороне все функции класса string не действуют на строку, но возвращают новый строковый объект, потому что строки неизменяемы.
@Jared:
Неперегруженные, не наследуемые статические методы (например, Class.b(a, c)), которые принимают экземпляр в качестве первой переменной, семантически эквивалентны вызову метода (например, a.b(c))
Нет, это не так.
(Предположим, что он скомпилирован с тем же CIL, что и должен.)
Это твоя ошибка. Выпуск CIL отличается. Различие заключается в том, что методы-члены не могут быть вызваны значениями null
, поэтому CIL вставляет проверку с значениями null
. Это явно не делается в статическом варианте.
Однако String.Format
не позволяет использовать значения null
, поэтому разработчикам необходимо вручную вставить проверку. С этой точки зрения вариант метода участника был бы технически превосходным.
Это во избежание путаницы с методами .ToString()
.
Например:
double test = 1.54d;
//string.Format pattern
string.Format("This is a test: {0:F1}", test );
//ToString pattern
"This is a test: " + test.ToString("F1");
Если формат был методом экземпляра в строке, это может вызвать путаницу, поскольку шаблоны отличаются.
String.Format() - это метод утилиты для преобразования нескольких объектов в форматированную строку.
Метод экземпляра в строке что-то делает с этой строкой.
Конечно, вы могли бы сделать:
public static string FormatInsert( this string input, params object[] args) {
return string.Format( input, args );
}
"Hello {0}, I have {1} things.".FormatInsert( "world", 3);
Я не знаю, почему они это сделали, но это уже не имеет значения:
public static class StringExtension
{
public static string FormatWith(this string format, params object[] args)
{
return String.Format(format, args);
}
}
public class SomeClass
{
public string SomeMethod(string name)
{
return "Hello, {0}".FormatWith(name);
}
}
Это намного проще, ИМХО.
Еще одна причина для String.Format
- это сходство с функцией printf
от C. Предполагалось, что разработчики C имеют более легкие языки переключения времени.
Большая цель дизайна для С# заключалась в том, чтобы сделать переход от C/С++ к нему максимально простым. Использование точечного синтаксиса в строковом литерале было бы очень странным для кого-то, у которого есть только фон C/С++, а форматирование строк - это то, что разработчик, вероятно, сделает в первый день с языком. Поэтому я считаю, что они сделали его статичным, чтобы приблизить его к привычной территории.
Я не вижу ничего плохого в том, что он статичен.
Семантика статического метода, похоже, имеет для меня гораздо больше смысла. Возможно, это потому, что это примитив. Когда примитивы используются часто, вы хотите сделать код утилиты для работы с ними как можно более легким. Кроме того, я думаю, что семантика намного лучше с String.Format над "MyString BLAH BLAH {0}". Формат...
Я еще не пробовал, но вы можете сделать метод расширения для того, что хотите. Я бы этого не сделал, но я думаю, что это сработает.
Также я нахожу String.Format()
больше в соответствии с другими статическими статическими методами, такими как Int32.Parse()
, long.TryParse()
и т.д.
Вы облака также просто используете StringBuilder
, если хотите нестатический формат.
StringBuilder.AppendFormat()
String.Format должен быть статическим методом, потому что строки являются неизменяемыми. Создание метода экземпляра подразумевает, что вы можете использовать его для "форматирования" или изменения значения существующей строки. Этого вы не можете сделать, и создание метода экземпляра, возвращающего новую строку, не имеет смысла. Следовательно, это статический метод.
Неперегруженные, не наследуемые статические методы (например, Class.b(a, c)), которые принимают экземпляр в качестве первой переменной, семантически эквивалентны вызову метода (например, ab (c)), поэтому команда платформы сделала произвольный, эстетический выбор. (Предполагая, что он скомпилируется с тем же CIL, каким он должен.) Единственный способ узнать, будет ли это спрашивать, почему.
Возможно, они сделали это, чтобы обе строки были близки друг к другу лексиграфически, то есть
String.Format("Foo {0}", "Bar");
вместо
"Foo {0}".Format("bar");
Вы хотите знать, к каким индексам сопоставляются; возможно, они думали, что часть ".Format" просто добавляет шум посередине.
Интересно, что метод ToString (по крайней мере для чисел) является противоположным: number.ToString( "000" ) с строкой формата справа.
String.Format
принимает по крайней мере одну строку и возвращает другую строку. Нет необходимости изменять строку формата, чтобы возвращать другую строку, поэтому делать это не имеет смысла (игнорируя ее форматирование). С другой стороны, было бы не так много, чтобы сделать String.Format
функцией-членом, за исключением того, что я не думаю, что С# допускает функции const-члена, такие как С++. [Пожалуйста, исправьте меня и этот пост, если это произойдет.]
Строки .NET неизменяемы
Поэтому наличие метода экземпляра абсолютно бессмысленно.
String foo = new String();
foo.Format("test {0}",1); // Makes it look like foo should be modified by the Format method.
string newFoo = String.Format(foo, 1); // Indicates that a new string will be returned, and foo will be unaltered.