Неявный приведение типа char к int в C # - PullRequest
33 голосов
/ 01 октября 2009

У меня вопрос по поводу неявного преобразования типов

Почему это неявное преобразование типов работает в C #? Я узнал, что неявный код обычно не работает.

У меня есть пример кода здесь о неявном преобразовании типов

 char c = 'a';
 int x = c;
 int n = 5;
 int answer = n * c;
 Console.WriteLine(answer);

Ответы [ 9 ]

75 голосов
/ 01 октября 2009

ОБНОВЛЕНИЕ: сегодня я использую этот вопрос в качестве темы моего блога. Спасибо за отличный вопрос. Пожалуйста, смотрите блог для будущих дополнений, обновлений, комментариев и т. Д.

http://blogs.msdn.com/ericlippert/archive/2009/10/01/why-does-char-convert-implicitly-to-ushort-but-not-vice-versa.aspx


Мне не совсем понятно, что именно вы спрашиваете. «Почему» на вопросы сложно ответить. Но я попробую.

Во-первых, код, который имеет неявное преобразование из char в int (примечание: это не «неявное приведение», это «неявное преобразование») является допустимым, поскольку в спецификации C # четко указано, что существует неявное преобразование из char to int, и в этом отношении компилятор является правильной реализацией спецификации.

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

Ну, во-первых, очевидные вещи, которые мешают этому правилу языка, не применяются. Символьный символ реализован в виде 16-разрядного целого числа без знака, которое представляет символ в кодировке UTF-16, поэтому его можно преобразовать в короткую строку без потери точности или, в этом отношении, без изменения представления. Среда выполнения просто переходит от обработки этого шаблона битов как символа к обработке того же шаблона битов, что и для ushort.

Поэтому возможно разрешить преобразование из char в ushort. То, что что-то возможно, не означает, что это хорошая идея. Очевидно, разработчики языка думали, что неявное преобразование char в ushort было хорошей идеей, но неявное преобразование ushort в char - нет. (И поскольку char для ushort - хорошая идея, кажется разумным, что char-to-everything-ushort-go-to также является разумным, следовательно, char to int. Кроме того, я надеюсь, что понятно, почему разрешение явное приведение ushort к char разумно; ваш вопрос касается неявных преобразований.)

Таким образом, у нас фактически есть два связанных вопроса: во-первых, почему плохая идея разрешать неявные преобразования из ushort / short / byte / sbyte в char? и во-вторых, почему стоит разрешить неявные преобразования из char в ushort?

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

Первый вопрос описан в примечаниях от 14 апреля 1999 г., где возникает вопрос о том, должно ли быть законным преобразование из байта в символ. В исходной предварительной версии C # это было законно в течение короткого времени. Я слегка отредактировал примечания, чтобы прояснить их без понимания кодовых имен Microsoft до 1999 года. Я также добавил акцент на важные моменты:

[Комитет по проектированию языков] решил предоставить неявное преобразование из байтов в символы, так как домен одного полностью сдерживается другим. Прямо сейчас, однако, [время выполнения библиотека] предоставляют только методы записи которые берут символы и целые, что означает что байты распечатываются как символы так как это оказывается лучшим метод. Мы можем решить это либо предоставляя больше методов на Writer класс или путем удаления неявного преобразование.

Есть аргумент, почему последнее - правильная вещь. В конце концов, байтов на самом деле не символы . Правда, может быть полезное отображение от байтов до символов, но в конечном итоге 23 не обозначает то же самое, что персонаж с ascii значение 23, так же, как 23B обозначает то же самое, что и 23L. Запрашиваемая [авторы библиотеки], чтобы обеспечить это дополнительный метод просто из-за как работает причуды в нашей системе типов кажется довольно слабым. Так что я бы предложить, чтобы мы сделали преобразование от байта к символу явно.

Затем примечания завершаются решением о том, что byte-char должен быть явным преобразованием, а целочисленное значение-в-диапазоне-char также должно быть явным преобразованием.

Обратите внимание, что в примечаниях к дизайну языка не указывается, почему ushort-to-char также был объявлен недопустимым одновременно, но вы можете видеть, что применяется та же логика. При вызове метода, перегруженного как M (int) и M (char), когда вы передаете ему ushort, есть хорошие шансы, что вы захотите рассматривать ushort как число, а не как символ. И ushort НЕ является символьным представлением так же, как ushort является числовым представлением, поэтому представляется разумным также сделать это преобразование незаконным.

Решение сделать так, чтобы чарс отправился в срочно, было принято 17 сентября 1999 г .; в заметках этого дня по этой теме просто говорится, что "символ в ushort также является законным неявным преобразованием", и все. Дальнейшее изложение того, что происходило в тот день у создателей языка, не видно в заметках.

Тем не менее, мы можем образовать догадки о том, почему неявный char-to-ushort считался хорошей идеей. Ключевой идеей здесь является то, что преобразование из числа в символ является «возможно хитрым» преобразованием. Он берет то, что вы НЕ ЗНАЕТЕ, предназначено для того, чтобы стать персонажем, и решает относиться к нему как к одному. Это похоже на то, что вы хотите отрицать, что вы делаете явно, а не случайно позволяете это. Но обратное гораздо менее хитроумно. В программировании на С существует давняя традиция рассматривать символы как целые числа - получать их базовые значения или делать на них математику.

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

Это отвечает на ваш вопрос?

12 голосов
/ 01 октября 2009

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

Таким образом, неявное преобразование из char в int будет работать в C #.

[править] Как отмечали другие, char - это 16-разрядное число в C #, поэтому это преобразование представляет собой просто 16-разрядное целое число и 32-разрядное целое число, что возможно без потери данных. [/ править]

C # поддерживает неявные преобразования, часть "обычно не работает", вероятно, происходит из другого языка, возможно, C ++, где некоторые замечательные реализации string обеспечивали неявные преобразования в различные типы указателей, создавая гигантские ошибки в приложениях. .

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

9 голосов
/ 01 октября 2009

Из спецификации C #

6.1.2 Неявные числовые преобразования Неявные числовые преобразования:

• От sbyte к короткому, int, long, float, double или decimal.

• От байта к короткому, ushort, int, Uint, длинный, Ulong, плавать, двойной или десятичный.

• От короткого до целого, длинного, плавающего, двойной или десятичный.

• От ushort к int, uint, long, ulong, float, double или decimal.

• От int к long, float, double или десятичный.

• От мятного к длинному, удлиненному, плавающему, двойной или десятичный.

• От длинного до плавающего, двойного или десятичный.

• От ulong до float, double или десятичный.

• От символа к ushort, int, uint, длинный, удлиненный, плавающий, двойной или десятичный.

• От поплавка к удвоению.

Преобразования из int, uint, long или продолговатое плавание и длинное или удлиненное удвоение может привести к потере точность, но никогда не приведет к потере величины. Другой неявный числовые преобразования никогда не теряют Информация. Там нет неявного преобразования в тип char, так значения других целочисленных типов делают не конвертировать автоматически в символ тип.

4 голосов
/ 01 октября 2009

Со страницы MSDN о типе char ( char (C # Reference) :

Символ может быть неявно преобразован в ushort, int, uint, long, ulong, float, double или decimal. Однако не существует неявных преобразований из других типов в тип char.

Это потому, что они реализовали неявный метод из char для всех этих типов. Теперь, если вы спросите, почему они их реализовали, я действительно не уверен, конечно, чтобы помочь работать с ASCII представлением символов или чем-то в этом роде.

1 голос
/ 01 октября 2009

Приведение приведет к потере данных. Здесь char - 16 бит, а int - 32 бит Таким образом, приведение произойдет без потери данных.

Пример из реальной жизни: мы можем поставить маленькое судно в большое, но не наоборот без внешней помощи.

0 голосов
/ 16 апреля 2019

Суть записи в блоге @Eric Lippert - это его обоснованное предположение о причинах такого решения разработчиков языка c #:

"There is a long tradition in C programming of treating characters as integers 
-- to obtain their underlying values, or to do mathematics on them."

Это может вызвать ошибки, такие как:

var s = new StringBuilder('a');

Как вы думаете, инициализация StringBuilder инициализируется символом 'a', , но фактически устанавливает емкость StringBuilder равной 97 .

0 голосов
/ 30 июля 2012

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

string ab = "ab";
char a = ab[0];
char b = ab[1];
var d = a + b;   //195

Мы поместили всю информацию из строки в символы. Если по какой-либо причине сохраняется только информация из d, нам остается только число, которое не имеет смысла в этом контексте и не может быть использовано для восстановления ранее предоставленной информации. Таким образом, наиболее полезным способом было бы косвенное преобразование «суммы» символов в строку.

0 голосов
/ 01 октября 2009

Символ неявно приводится к его числовому значению Unicode, которое является целым числом.

0 голосов
/ 01 октября 2009

Это работает, потому что каждый символ обрабатывается внутри как число, поэтому приведение неявно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...