Преобразование типа переменной
Совсем недавно стал изучать C#
Почему этот код неправильный?
int num = 4;
num = num.ToString();
Неужели всегда нужно создавать новую переменную, как в примере ниже?
int num = 4;
string str = num.ToString();
Совсем недавно стал изучать C#
Почему этот код неправильный?
int num = 4;
num = num.ToString();
Неужели всегда нужно создавать новую переменную, как в примере ниже?
int num = 4;
string str = num.ToString();
В C# всё имеет тип. Типы могут наследоваться друг от друга, самый старший тип, от которого логически наследуются все остальные типы - это object
.
C# имеет строгую типизацию. Чтобы задать переменную или объявить член класса, нужно определить её тип. Тип задается при объявлении переменной и далее не изменяется.
Можно ли использовать тот самой тип object
для того что вы хотите сделать? Можно.
object num = 4;
num = num.ToString();
Но так никто не делает, потому что далее работать с переменной num
неудобно. Например нельзя сделать так.
object num = 4;
num = num + 1; // ошибка: Operator '+' cannot be applied to operands of type 'object' and 'int'
Дополнительно к этим проблемам добавляется то что object
- это ссылочный тип, а int
- значимый, компилятор создаст обертку вокруг int
(boxing) и код получится неоптимальный. Поэтому следует использовать явные конкретные типы, так будет работать быстрее.
Кстати для значимых типов вроде int
при присваивании не выделяется память на безусловной основе. Скорей всего после компиляции переменная будет жить только в регистре процессора или же место под её хранения будет выделено в стеке, это происходит очень быстро и не требует последующей сборки мусора.
Другими словами, не стоит переживать, что вы создаете новые переменные. Компилятор очень умный, вот вам пример:
int a = 3;
int b = 4;
int c = a + b;
Console.WriteLine(c);
Как вы думаете, что получится, если этот код скомпилировать, а потом декомпилировать? А вот что:
Console.WriteLine(7);
А вот из этого кода
string hello = "Hello";
string hello = "World";
Console.WriteLine(hello + " " + world);
Получится
Console.WriteLine("Hello World");
То есть компилятор, оптимизируя код, сам понял при сборке приложения что вы больше нигде и никак не изменяете переменные, и он сам воспринял их как константы и провел необходимые оптимизации ещё до компиляции.
Конечно, при отладке никаких таких оптимизаций не будет, чтобы не помешать вам пошагово отлаживать код. А вот в релизной (Release) сборке она будет, за это отвечает галочка "Оптимизировать код" в настройках профиля сборки.
Поэтому пока не заморачивайтесь сильно о расходах ресурсов, учитесь писать код, корректно выполняющий поставленные задачи, а компилятор позаботится об остальном. С опытом вы научитесь контролировать аллокации (создание new
объектов), память и писать мощные оптимизации. Но сейчас такие знания могут лишь создать много сложных и ненужных новичку вопросов. Хотя, если вам очень интересно, почитайте про Сборщик мусора (Garbage Collector) и про CLR в целом (Common Language Runtime), там всё про работу с памятью расписано.
Кстати, тип string
является ссылочным и неизменяемым. То есть однажды созданная строка уже не может быть изменена в будущем, а конкатенация и прочие операции со строками приводят к выбрасыванию ранее созданных строк и созданию новых.
string hello = "Hello";
string world = hello; // обе ссылки указывают на один и тот же объект
Console.WriteLine(hello.ReferenceEquals(world)); // True
world = hello + " World";
Console.WriteLine(hello) // "Hello"
Это потому что была создана новая строка и ссылка на нее была помещена в переменную world
. А если бы строка была изменяемым типом, вывод был бы другой. В этом есть свои плюсы и минусы, плюсы в том что если откуда-то вам пришла строка, то есть гарантия, что в каком-то другом потоке ее никто не изменит (многопоточность). А минусы - выделение памяти каждый раз когда надо строку изменить, но это можно объехать, для этого существуют специальные классы, например StringBuilder
или методы для быстрого создания строк с известной длиной типа string.Create
. Вот такие вот фокусы.
Почему этот код неправильный? Потому, что переменная num объявлена как переменная типа int, и она не помет принять значение num.ToString() типа string.
Неужели всегда нужно создавать новую переменную, как в примере ниже? Невсегда. Если нужно сохранять значения такого же типа, то можно новую и не создавать. Но это может быть не очень хорошо с точки зрения понимания кода.
Вообще, экономить на именах переменных нет никакой выгоды - сейчас даже не нужно печатать текст программы на бумаге. Имена переменных важны только для компилятора в подавляющем большинстве случаев. Так что нет никаких причин не создавать новые переменные, когда они нужны. Имеет смысл только информация, которая в них хранится.
Нужно учитывать, что в c#, как и в большинстве языков, объявление новой переменной влечёт за собой выделение памяти. (Это можно проигнорировать: "Не знаю, как в Питоне, а в Руби появление новой переменной далеко не всегда означает выделение памяти. Память выделяется только под объект, а переменных для этого объекта в программе можно насоздавать сколько угодно, и они будут всего лишь псевдонимами друг друга." Дальше дообсуждались до того, что память выделяется, хоть и под таблицу переменных, но разницы, по сути, нет.)
Нельзя не добавить, что есть тип object, и ему можно присваивать любые значения:
object num = 4;
num = num.ToString();