Здесь есть много неправильных представлений, как в самом вопросе, так и в нескольких ответах.
Позвольте мне начать рассмотрение предпосылки вопроса. Вопрос в том, «зачем нам нужно ключевое слово new
в C#?» Мотивация вопроса заключается в этом фрагменте C++:
MyClass object; // this will create object in memory
MyClass* object = new MyClass(); // this does same thing
Я критикую этот вопрос на двух основаниях.
Во-первых, они не делают то же самое в C++, поэтому вопрос основан на ошибочном понимании языка C++. очень важно понять разницу между этими двумя вещами в C++, поэтому, если вы не очень четко понимаете, в чем разница, найдите наставника, который может научить вас, как узнать, в чем разница, и когда использовать каждый ,
Во-вторых, вопрос предполагает - неверно, что эти два синтаксиса выполняют одно и то же в C++, а затем, как ни странно, спрашивает: «Почему нам нужно new
в C#?» Разумеется, правильный вопрос, который следует задать, - это опять-таки ложная предпосылка: «зачем нам new
в C++?» Если эти два синтаксиса делают то же самое, чего нет, то почему у вас есть два синтаксиса?
Таким образом, вопрос основывается на ложной предпосылке, и вопрос о C# на самом деле не вытекает из - непонятого - дизайна C++.
Это беспорядок. Давайте вышлем этот вопрос и зададим несколько более сложных вопросов. И давайте зададим вопрос о C# qua C#, а не в контексте проектных решений C++.
Что делает оператор new X
в C#, где X - класс или тип структуры? (Давайте игнорировать делегатов и массивы для целей этой дискуссии.)
Новый оператор:
- Вызывает новый экземпляр данного типа, которые будут выделены; новые экземпляры имеют все поля, инициализированные значениями по умолчанию.
- Вызывает конструктор данного типа для выполнения.
- Производит ссылку на выделенный объект, если объект является ссылочным, или само значение, если объект является типом значения.
Хорошо, я уже слышу возражения от программистов на C# там, поэтому давайте их отстраняем.
Возражение: нет нового хранилища, если тип является типом значения, я слышу, что вы говорите. Ну, спецификация C# не согласна с вами. Когда вы говорите
S s = new S(123);
для некоторой структуры типа S
, спецификация говорит, что новое временное хранение выделяется на краткосрочный пул, инициализируются значениями по умолчанию, конструктор работает с this
набором, чтобы обратиться к и затем результирующий объект скопировал в s
. Однако компилятор разрешил использовать оптимизацию при копировании, при условии, что он может доказать, что оптимизация не может наблюдаться в безопасной программе. (Упражнение: выясните, при каких обстоятельствах не может быть выполнено копирование, дайте пример программы, которая имела бы разные типы поведения, если бы элиция была или не использовалась.)
Возражение: действительным экземпляром типа значения может быть с использованием default(S)
; никакой конструктор не вызван, слышу вы говорите. Правильно. Я не сказал, что new
является только способ создания экземпляра типа значения.
Фактически, для значения типа new S()
и default(S)
- это то же самое.
Возражение: Является ли конструктор действительно выполненным для ситуаций, таких как new S()
, если не присутствует в исходном коде на C# 6, я слышу, что вы говорите. Это «если дерево падает в лес, и никто его не слышит, это звучит?» вопрос. Есть ли разница между вызовом конструктора, который ничего не делает, и вообще не звонит? Это не интересный вопрос. Компилятор может свободно выполнять вызовы, которые он знает, ничего не делает.
Предположим, что у нас есть переменная типа значения. Нужно ли инициализировать переменную экземпляром, созданным new
?
No. Переменные, которые автоматически инициализируются, такие как поля и элементы массива, будет инициализирован значением по умолчанию - то есть, значение структуры, где все поля являются сами их значения по умолчанию.
Формальные параметры будут, очевидно, инициализированы аргументом.
Локальные переменные типа значения должны быть обязательно назначены чем-то перед чтением полей, но это не должно быть выражение new
.
Так эффективно переменные типа значения автоматически инициализируются эквивалентом default(S)
, если только они не являются местными жителями?
Да.
Почему бы не сделать то же самое для местных жителей?
Использование неинициализированного локального файла сильно связано с кодовым кодом. Язык C# запрещает это, потому что при этом обнаруживаются ошибки.
Предположим, что у нас есть переменная ссылочного типа. Должен ли мы инициализировать S
экземпляром, созданным new
?
№ п. Параметры автоматической инициализации будут инициализированы нулевым значением. Местные жители могут быть инициализированы с любой ссылкой, включая null
и должны быть обязательно назначены перед чтением.
Таким образом, переменные ссылочного типа автоматически инициализируются null
, если только они не являются местными жителями?
Да.
Почему бы не сделать то же самое для местных жителей?
По этой же причине. Вероятная ошибка.
Почему бы не автоматически инициализировать переменные ссылочного типа, вызвав конструктор по умолчанию автоматически? То есть, почему бы не сделать R r;
так же, как R r = new R();
?
Ну, во-первых, многие виды не имеют конструктор по умолчанию, или в этом отношении, любой доступный конструктор по всем. Во-вторых, кажется странным иметь одно правило для неинициализированного локального или поля, другое правило для формального и еще одно правило для элемента массива. В-третьих, существующее правило очень просто: переменная должна быть инициализирована значением; это значение может быть любым, что вам нравится; Почему предположение, что требуется новый экземпляр, гарантируется? Было бы странно, если бы это
R r;
if (x) r = M(); else r = N();
вызывается конструктор для запуска инициализации r
.
Оставляя в стороне семантику оператора new
, почему необходимо синтаксически иметь такой оператор?
Это не так. Существует несколько альтернативных синтаксисов, которые могут быть грамматическими. Наиболее очевидным было бы просто полностью исключить new
. Если у нас есть класс C
с конструктором C(int)
, тогда мы могли бы просто сказать C(123)
вместо new C(123)
. Или мы могли бы использовать синтаксис, например, C.construct(123)
или некоторые такие вещи. Существует несколько способов сделать это без оператора new
.
Так почему?
Во-первых, C# был разработан, чтобы быть немедленно знакомы пользователям C++, Java, JavaScript и другие языки, которые используют new
для указания нового хранилища для инициализации объекта.
Во-вторых, желателен высокий уровень синтаксической избыточности. Создание объекта является особенным; мы хотим вызывать, когда это происходит со своим собственным оператором.
Вот как C# есть. Для создания нового экземпляра класса вам понадобится 'new', поэтому это будет' Car x = new Car(); ' – Pikoh
Я часто говорил, что проще перейти от C++ к C# или Java, чем к другой способ вокруг. Имея четкое понимание основ C++, сбор C# или Java довольно прост. Но оба они делают так много вещей под обложками и которые, как правило, не очень хорошо объясняются в традиционных ресурсах, которые учат C# и Java, что при переходе от любого из этих двух к C++ это всегда очень и очень разочаровывает. –
Btw, 'Myclass object;' делает что-то отличное от 'Myclass * object = new MyClass();' – MaciekGrynda