Причины создания ToUpper статического метода на Char

В С# у нас есть этот нестатический метод для строки типа:

"abc".ToUpper()

но для char нам нужно использовать статический метод:

char.ToUpper('a')

При введении С# новичкам они всегда ожидают, что смогут написать следующее:

'a'.ToUpper()

Кто-нибудь знает, почему он был спроектирован так?

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

Ответы

Ответ 1

Разница заключается в том, что string является ссылочным типом, а char - это ключевое слово, которое представляет .Net Framework Char Структура. Когда вы вызываете Char.ToUpper('a'), вы фактически используете структуру Char в С#. Структуры Типы значений. Типы значений неизменяемы.

Поскольку структуры неизменяемы, методы, которые воздействуют на структуру, не работают должным образом (см. Почему Mutable Structs Evil). Таким образом, необходимы статические методы. При вызове Char.ToUpper(aChar) вы фактически не меняете aChar, вместо этого вы создаете новый экземпляр символа, который является прописным представлением символа, который вы передали в качестве параметра, и возвращающего его. Пример ниже демонстрирует это.

Char aChar = 'a';
Char.ToUpper(aChar);
//aChar still equals 'a'

Char bChar = 'b';
bChar = Char.ToUpper(bChar);
//bChar now equals 'B'

Причина Char имеет другие методы, позволяющие делать такие вещи, как 'a'.Equals('a');, потому что типы значений и ссылочные типы наследуются от Object, который определяет эти методы (технически, типы значений имеют тип System.ValueType, который наследует от System.Object). Эти методы не вносят никаких изменений в сам объект.

Изменить - почему этот вопрос на самом деле является предположением

Как мне очень любопытно узнать, есть ли реальный ответ на вопрос "почему char не имеет метода .ToUpper()", я решил проверить Документ спецификации языка CSharp 5, я нашел следующее:

char является интегральным типом (pg 80), который является подмножеством простых типов. Простые типы сами по себе являются предопределенными типами Struct. Типы типов - это типы значений, которые "могут объявлять константы, поля, методы, свойства, индексы, операторы, конструкторы экземпляров, статические конструкторы и вложенные типы" (стр. 79).

string - тип класса, который является ссылочным типом (pg 85). Типы классов определяют "структуру данных, которая содержит члены данных (константы и поля), члены функций (методы, свойства, события, индексы, операторы, конструкторы экземпляров, деструкторы и статические конструкторы) и вложенные типы" (стр. 84).

На этом этапе очевидно, что char может поддерживать метод .ToUpper() (поэтому работает метод расширения). Однако, как говорится в этом вопросе, они не поддерживают его. В этот момент я убежден, что любые рассуждения о том, почему это так, - это чистое предположение (если вы, конечно, не работаете в команде С#).

Ответ 2

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

public static class MyExtensionMethods
{
    public static char ToUpper( this char c )
    {
        return char.ToUpper( c );
    }
}

Затем вы можете сделать:

'a'.ToUpper()

Ответ 3

(извините, недостаточно места в комментарии - я знаю, что это не полный ответ.)

Кажется, это образец для всех примитивных типов; int, double и bool, например, также не имеют методов (кроме вариантов ToString()). Таким образом, это не просто char - это свойство всех примитивных типов, которые определяет С#.

Я бы предположил (и это предположение), что каждый раз, когда вы обращаетесь к данным, вы либо напрямую получаете доступ к битам ОЗУ - примитивные значения, такие как int и char и byte - или вы 'обращение к .NET-конструкту как объект или структура. A char всегда имеет 2 байта на конкретном адресе памяти. Таким образом, структура может обрабатывать его как место необработанной памяти.

Если мы попытаемся обработать необработанную RAM как объекты, вам придется либо "вставить" все, чтобы выполнить какую-либо работу, либо это просто невозможно. Я предполагаю, что вы не можете сделать некоторые основные функции, такие как отправка виртуальных методов на примитивах, и что мир объектов и мир примитивов должен быть раздельным.

В любом случае, надеюсь, что эта беседа продвинется на определенном уровне...