Почему String.Format статичен?

Сравнивать

String.Format("Hello {0}", "World");

с

"Hello {0}".Format("World");

Почему дизайнеры .Net предпочли статический метод методу экземпляра? Что вы думаете?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
39
0
4 972
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Я думаю, это потому, что это метод создателя (не уверен, что есть лучшее название). Все, что он делает, это берет то, что вы ему даете, и возвращает единственный строковый объект. Он не работает с существующим объектом. Если бы он был нестатическим, вам для начала понадобится строка.

Потому что метод Format не имеет ничего общего с текущим значением строки. Значение строки не используется. Он берет строку и возвращает ее.

Я не вижу ничего плохого в том, что это статично ...

Мне кажется, что семантика статического метода имеет больше смысла. Возможно, это потому, что он примитивен. Там, где примитивы используются часто, вы хотите сделать код утилиты для работы с ними как можно более легким ... Кроме того, я думаю, что семантика намного лучше с String.Format по сравнению с "MyString BLAH BLAH {0}". Формат ...

Нет ничего плохого в том, что он статичен; Причина, по которой я задумался об этом, заключалась в том, что он увеличивает длину по сравнению с "my {0} string".Format(args) и усложняет переключение строкового литерала на форматированную строку. Не очень, но достаточно, чтобы использовать метод экземпляра.

ehdv 03.05.2012 18:11

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

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

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

Также я считаю, что String.Format() больше соответствует другим шаблонным статическим методам, таким как Int32.Parse(), long.TryParse() и т. д.

Вы также можете использовать StringBuilder в облаке, если хотите нестатический формат. StringBuilder.AppendFormat()

String.Format принимает хотя бы одну строку и возвращает другую строку. Нет необходимости изменять строку формата, чтобы вернуть другую строку, поэтому это не имеет смысла (игнорируя ваше форматирование). С другой стороны, было бы не так уж сложно сделать String.Format функцией-членом, за исключением того, что я не думаю, что C# допускает константные функции-члены, как это делает C++. [Пожалуйста, исправьте меня и этот пост, если это так.]

Я думаю, что в целом лучше использовать String.Format, но я мог видеть смысл в желании иметь нестатическую функцию, когда у вас уже есть строка, сохраненная в переменной, которую вы хотите «отформатировать».

Кстати, все функции строкового класса не работают со строкой, а возвращают новый строковый объект, потому что строки неизменяемы.

Но наличие статического String.Format, в то время как другие методы, такие как Trim и PadLeft, не являются несовместимыми.

Alex Lowe 29.07.2020 17:40

Because the Format method has nothing to do with a string's current value.

Это верно для строковых методов все, потому что строки .NET неизменяемы.

If it was non-static, you would need a string to begin with.

Это делает: строка формата.

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

почему это не принятый ответ?

Tim 23.12.2008 19:29

@tim: потому что я думаю, что ответ Эндрюса лучше. :-)

Jakub Šturc 28.06.2009 12:52

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

Konrad Rudolph 28.06.2009 15:01

Отражение дает "неизменному" новый синоним: изменчивый ...: P

Humphrey Bogart 23.02.2010 20:25

String.Format должен быть статическим методом, потому что строки неизменяемы. Создание метода экземпляра подразумевает, что вы можете использовать его для «форматирования» или изменения значения существующей строки. Вы не можете этого сделать, и делать его методом экземпляра, возвращающим новую строку, не имеет смысла. Следовательно, это статический метод.

Чем формат отличается от замены или подстроки? Фактические строки не меняются, возвращаются новые. Формат мог последовать его примеру.

Greg 17.02.2010 23:52

Верно, но подумайте об этом так: если бы Format был методом экземпляра, вам нужно было бы объявить свою строку, а затем вызвать для нее Format. Это всегда будет двухэтапный процесс. Например. 1) строка strTemp; 2) strTemp.Format ("{0}", "Hello World"); Очиститель, чтобы сделать его статичным.

user2189331 23.02.2010 20:28

И семантически говоря, Replace и Substring имеют смысл как методы экземпляра. Форматирование могло быть любым, но использование более чистое, если оно статично.

user2189331 23.02.2010 20:32

Что ж, я думаю, вы должны быть довольно разборчивы в этом, но, как люди говорят, для 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.

Ваш второй пример действительно не подходит для таких вещей, как "a b c".Replace("a", "kitty"), IMO.

davidtbernal 20.03.2011 04:10

Может быть, дизайнеры .NET сделали это, потому что JAVA сделала это так ...

Обними и простирайся. :)

См .: http://discuss.techinterview.org/default.asp?joel.3.349728.40

AFAIK метод .NET старше, чем метод Java (Java получил его только в версии 5).

Joachim Sauer 09.03.2009 16:34

Хм? Java 1.5: java.sun.com/j2se/1.5.0/docs/api/java/lang/…

jm. 21.03.2009 01:16

@jm: По странным маркетинговым причинам, наиболее известным Sun, Java 1.5 и Java 5 - одно и то же.

Simon Nickerson 01.10.2009 17:41

Первое, что я сделал при обновлении до VS2008 и C# 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 выбрали его? Кто знает. Это кажется полностью субъективным. Мои деньги либо на

  • Копирование Java
  • Парню, писавшему ее в то время, субъективно она понравилась больше.

На самом деле нет других уважительных причин, которые я могу найти

Я не думаю, что метод расширения - правильный путь. Я создаю интересный момент для читателя. Я считаю, что в C# мы застряли на статической версии.

Jakub Šturc 28.06.2009 12:59

Это субъективно, @Jakub. Для меня - я сразу понимаю, что это правильно, когда вижу скрученные брекеты.

Arnis Lapsa 23.02.2010 20:24

Я не уверен, что такое «момент wft», но чем он отличается от любого другого использования методов расширения?

Ken 23.02.2010 20:33

Я делаю это и помещаю его в пространство имен System, где находится String.

Kugel 15.07.2010 15:41

Строки .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.

Это несовместимо с другими операциями String, которые являются методами экземпляра и возвращают новые строки. Insert, Normalize, PadLeft и т. д. Все работают точно так, как описано. Если Format является статическим, потому что строки неизменяемы, тогда все они также должны быть статическими, а это не так.

Alex Lowe 29.07.2020 17:30

Неперегруженные, ненаследуемые статические методы (например, Class.b (a, c)), которые принимают экземпляр в качестве первой переменной, семантически эквивалентны вызову метода (например, ab (c)), поэтому команда разработчиков платформы сделала произвольный, эстетический выбор. (Предполагая, что он компилируется в тот же CIL, что и должен.) Единственный способ узнать это - спросить их, почему.

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

String.Format("Foo {0}", "Bar");

вместо

"Foo {0}".Format("bar");

Вы хотите знать, на что отображаются индексы; возможно, они думали, что часть ".Format" просто добавляет шума в середине.

Интересно, что метод ToString (по крайней мере, для чисел) противоположен: number.ToString («000») со строкой формата справа.

.NET Strings are Immutable
Therefore having an instance method makes absolutely no sense.

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

Я согласен с тем, что, если бы они сделали его методом экземпляра, Format, похоже, был бы плохим именем, но это не значит, что функциональность не должна быть методом экземпляра.

Почему не это? Это соответствует остальная частьплатформа .NET

"Hello {0}".ToString("Orion");

@ Джаред:

Non-overloaded, non-inherited static methods (like Class.b(a,c)) that take an instance as the first variable are semantically equivalent to a method call (like a.b(c))

Нет, это не так.

(Assuming it compiles to the same CIL, which it should.)

Это твоя ошибка. CIL производится иначе. Различие в том, что методы-члены не могут быть вызваны для значений null, поэтому CIL вставляет проверку значений null. Очевидно, что в статическом варианте этого не происходит.

Однако String.Format не разрешает нет значений null, поэтому разработчикам пришлось вставлять проверку вручную. С этой точки зрения вариант метода члена будет технически лучше.

Я думаю, это была очень полезная парадигма, когда кто-то (Python) сказал мне думать о функциях-членах как о статических функциях с явным объектом this в качестве первого элемента. Спасибо за вдумчивый отзыв о нулях! Кстати, перегрузка добавляет больше сложностей к эквивалентности статического / членского метода.

Jared Updike 28.01.2009 03:06
Ответ принят как подходящий

На самом деле я не знаю ответа, но подозреваю, что это как-то связано с аспектом прямого вызова методов для строковых литералов.

Если я правильно помню (я на самом деле не проверял это, потому что у меня нет под рукой старой IDE), в ранних версиях C# IDE были проблемы с обнаружением вызовов методов для строковых литералов в IntelliSense, и это сильно влияло на обнаруживаемость API. Если бы это было так, ввод следующего кода не помог бы вам:

"{0}".Format(12);

Если бы вас заставили ввести

new String("{0}").Format(12);

Было бы ясно, что не было преимуществ в том, чтобы сделать метод Format методом экземпляра, а не статическим методом.

Библиотеки .NET были разработаны множеством тех же людей, которые дали нам MFC, и, в частности, класс String очень похож на класс CString в MFC. MFC действительно имеет метод форматирования экземпляра (который использует коды форматирования стиля printf, а не стиль фигурных скобок .NET), что болезненно, потому что не существует такой вещи, как литерал CString. Итак, в кодовой базе MFC, над которой я работал, я много чего вижу:

CString csTemp = "";
csTemp.Format("Some string: %s", szFoo);

что болезненно. (Я не говорю, что приведенный выше код - отличный способ делать что-то даже в MFC, но похоже, что именно так большинство разработчиков проекта научились использовать CString :: Format). Исходя из этого наследия, я могу представить, что разработчики API снова пытались избежать подобной ситуации.

... Значит, он так спроектирован из-за некомпетентности дизайна IDE?

Humphrey Bogart 23.02.2010 20:24

Тогда почему бы им не добавить форму "".Format позже, когда IDE стала лучше? Насколько я знаю, он ничего не ломает.

Chiel ten Brinke 13.01.2016 16:56

Это сделано во избежание путаницы с методами .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");

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

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 / C++ к нему как можно проще. Использование точечного синтаксиса в строковом литерале может показаться очень странным для кого-то, имеющего только опыт работы на C / C++, а форматирование строк - это то, что разработчик, вероятно, сделает в первый же день работы с языком. Поэтому я считаю, что они сделали его статичным, чтобы приблизить его к знакомой территории.

Я думаю, это потому, что Format принимает не строку как таковую, а «строку формата». Большинство строк эквивалентны таким вещам, как «Bob Smith» или «1010 Main St» или что у вас есть, а не «Hello {0}», обычно вы вставляете эти строки формата только тогда, когда пытаетесь использовать шаблон для создания другого string, как фабричный метод, и поэтому предоставляет себя статическому методу.

На данный момент это кажется лучшим ответом. Однако, если он должен быть `отличным от строки ', тогда зачем вообще помещать его в класс String ...

Thomas Ahle 06.04.2014 15:00

Другие вопросы по теме