Непоследовательность сборки инициализатора словаря С#
Следующий код компилируется, но с ошибкой NullReferenceException
:
class Test
{
public Dictionary<string, string> Dictionary { get; set; }
}
static void Main(string[] args)
{
var x = new Test
{
Dictionary = // fails
{
{ "key", "value" }, { "key2", "value2" }
}
};
}
Если вы замените строку с пометкой "fail" следующим образом, она работает (как и ожидалось):
Dictionary = new Dictionary<string, string>
Есть ли какая-либо цель синтаксиса неудачи - может ли он успешно использоваться в каком-либо другом случае? Или это недосмотр в компиляторе?
Ответы
Ответ 1
Нет, это не ошибка... это недостаток в вашем понимании синтаксиса инициализации:)
Идея
Dictionary = { ... }
предназначен для случаев, когда вызывающий абонент имеет доступ к доступу к свойству коллекции, но не к доступу на запись. Другими словами, такие ситуации:
class Test
{
private readonly Dictionary<string, string> dictionary
= new Dictionary<string, string>();
public Dictionary<string, string> Dictionary { get { return dictionary; } }
}
В основном это вызовы для добавления, но без создания новой коллекции. Итак, этот код:
Test test = new Test { Dictionary = { { "a", "b"}, {"c", "d" } };
эквивалентно:
Test tmp = new Test();
Dictionary<string, string> tmpDictionary = tmp.Dictionary;
tmpDictionary.Add("a", "b");
tmpDictionary.Add("c", "d");
Test test = tmp;
Хорошим примером того, где это полезно, является коллекция Controls
для пользовательского интерфейса. Вы можете сделать это:
Form form = new Form
{
Controls =
{
new Button { Text = "Hi" },
new TextBox { Text = "There" }
}
};
но вы не можете установить свойство Controls
, потому что оно доступно только для чтения.
Ответ 2
Вы все равно можете использовать синтаксис, который вы хотите в конструкторе:
Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{"a", "b"},
{"c", "d"}
};
Ответ 3
Не удалось выполнить исключение с нулевой ссылкой, потому что вы объявили переменную (словарь), которая не инициализирована, поэтому она равна null.
При попытке добавить записи в него с использованием синтаксиса инициализатора вы пытаетесь записать данные в нулевой объект.
Когда вы заменяете строку "= новый словарь...", вы создаете новый объект для словаря для ссылки, и, следовательно, вы можете успешно добавить записи в него.
(В примере с Jon Skeet коллекция элементов управления уже была создана формой, поэтому она работает нормально)