В чем разница между объявлением класса null и созданием экземпляра класса?

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

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();

vs

Dictionary<int, List<string>> myDictionary = null;

Я знаю, что первая строка создает новый объект словаря, но поскольку я ничего не добавлял в словарь, это просто пустой объект. Вторая строка — это просто пустой объект словаря. Есть ли разница?


person d1du    schedule 11.07.2016    source источник
comment
Вы могли бы использовать свой отладчик и выяснить это самостоятельно?!?   -  person Uwe Keim    schedule 11.07.2016
comment
Null указывает на отсутствие объекта. Здесь мы видим некоторую информацию и факты о нулевом литерале (null). Null представлен значением 0, но вы не можете использовать 0 вместо null в своих программах. Null вызывает множество исключений.   -  person Gehan Fernando    schedule 11.07.2016
comment
Попробуйте вызвать .Count на обоих — скоро вы увидите разницу!   -  person CompuChip    schedule 11.07.2016
comment
Возможный дубликат Что такое null в Java? ИЛИ Что такое null в С#, Java?   -  person Draken    schedule 11.07.2016
comment
Спасибо за все ответы без троллей. Downvoters, получите lyfe pl0x.   -  person d1du    schedule 08.10.2016


Ответы (6)


В первом случае:

     Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
     myDictionary.Add(key,value); // NOT throw null reference exception.

Во втором случае:

     Dictionary<int, List<string>> myDictionary = null;
     myDictionary.Add(key,value); // will throw null reference exception.

Чтобы использовать любой объект коллекции, вам нужно сначала создать заполнитель.

person Gaurava Agarwal    schedule 11.07.2016
comment
Я предлагаю вам изменить ваши примеры на такие, которые будут компилироваться, и использовать терминологию C#, а не терминологию Java (исключение null reference, а не исключение null pointer) - person Jon Skeet; 11.07.2016

Думайте об этом следующим образом:

Переменная — это пустая бумага. Вы можете или не можете написать на нем адрес, который приведет вас в какое-то место.

Первая строка пишет на бумаге адрес объекта (созданного после нового ключевого слова).

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

В коде:

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
myDictionary.Add(1, "1"); // OK, myDictionary points to an address of
                         // Dictionary object and I can access it.

Пока:

Dictionary<int, List<string>> myDictionary = null;
myDictionary.Add(1, "1");  // Fails at run-time, I have no address for a Dictionary object 
                           // here AKA : NullReferenceException

Неверные утверждения вы сказали:

Вы не объявляете класс null, как вы сказали, вы создаете переменную, указывающую на null.

Вторая строка не является пустым объектом словаря, как вы сказали. Это переменная типа Dictionary, указывающая на NULL. В памяти нет пустого объекта словаря.

person Zein Makki    schedule 11.07.2016

Первая строка фактически создает объект (память выделяется); это означает, что у вас есть что-то, на что можно ссылаться и на что воздействовать (например, myDictionary.Count() вернет 0). Код if (null == myDictionary) будет оцениваться как false.

Вторая строка не создает никаких объектов; у вас есть ссылка ни на что (и в этом случае вызов myDictionary.Count() приведет к созданию исключения NullReferenceException). Код if (null == myDictionary) будет оцениваться как true.

person Jacob Pitts    schedule 11.07.2016
comment
Не то чтобы вы использовали условия Yoda в C#, как правило... - person Jon Skeet; 11.07.2016
comment
@Jon Старые привычки умирают с трудом :) - person Jacob Pitts; 11.07.2016

Вторая строка не является пустым объектом словаря. Попробуйте добавить материал во второй объект словаря, чтобы выяснить это самостоятельно. Обычно вы указываете ссылку на null, когда вы действительно хотите присвоить объект этой ссылке позже в программе.

person Geek    schedule 11.07.2016

Простой ответ. В первом случае вы можете его использовать. Во втором случае вы получите NullReferenceException пока вы продолжаете, потому что null означает, что он не существует, поэтому вы не можете получить к нему доступ, пока он не будет создан.

Во втором объявлении нет ничего плохого, но если вы хотите использовать это, значит, вам нужно создать их экземпляр (перед использованием), в противном случае он выдаст NullReferenceException. Пусть PopulateDictonary() будет методом, который вернет объект Dictionary, тогда вы можете использовать этот метод для создания экземпляра myDictionary.

То есть:

Dictionary<int, List<string>> myDictionary;
// Some code here, Not using myDictionary
myDictionary = PopulateDictonary();

Примечание. Перед использованием myDictionary следует проверить значение Null, если вы используете условное создание экземпляра объекта, чтобы избежать исключения.

person sujith karivelil    schedule 11.07.2016
comment
Он называется NullReferenceException. - person Uwe Keim; 11.07.2016
comment
Я собирался написать то же самое. Я могу добавить к этому ответу, что первый экземпляр вы создаете, а во втором вы только объявляете его. Для его использования вы должны создать экземпляр, а не только объявить. - person matiaslauriti; 11.07.2016
comment
Это на самом деле не объясняет разницу четко. Возможно, позже переменной будет присвоено другое значение... может быть, ей будет присвоено значение условно... и использование ссылки null может быть приемлемым. Например, его можно передать в качестве аргумента другому методу, который может обрабатывать значение параметра null. NullReferenceException будет выброшено только в том случае, если код попытается разыменовать значение. - person Jon Skeet; 11.07.2016
comment
@JonSkeet: позвольте мне объяснить - person sujith karivelil; 11.07.2016
comment
Я бы удалил все о значениях по умолчанию - это не имеет значения, если это объявление локальной переменной. И снова переменная может использоваться для передачи значения чему-то другому, но при этом иметь нулевое значение. - person Jon Skeet; 11.07.2016
comment
@JonSkeet: спасибо за ценные предложения и поддержку - person sujith karivelil; 11.07.2016

Между двумя операторами есть много различий, самое основное из них: первое — это инициализация, а второе — просто объявление. Рассмотрим следующий код:

Base b = new Derived();

В направлении

Base b = null;

В первом операторе вы создаете новый экземпляр Derived и назначаете его b. Обычно вам нужен экземпляр класса для вызова его членов (для простоты мы опускаем здесь статические члены), в вашем случае, например, Add-метод, определенный в Dictionary. С помощью декларации вы просто определяете члены, которые вы можете вызывать для экземпляра класса, однако ничего не говорится об экземпляре, для которого вы вызываете эти члены. Таким образом, в основном вам нужны две информации: код-контракт, который определяется используемым вами интерфейсом (не значением ООП) - в вашем случае это просто Dictionary<int, List<string>>. Теперь вы знаете, что делать с экземпляром этого класса. Однако у вас не будет иметь экземпляр класса, пока вы используете null-назначение. Это вторая информация - собственно экземпляр.

Чтобы остаться в моем предыдущем примере, как компилятор должен знать, какой класс вы на самом деле используете — Base или Derived. Это не обязательно повлияет на что вы можете делать с экземпляром (что дается определением в Base), но более того, как вы это делаете, поскольку Derived может иметь свою собственную логику. для выполнения действий, определенных в Base.

person HimBromBeere    schedule 11.07.2016