Непоследовательность сборки инициализатора словаря С#

Следующий код компилируется, но с ошибкой 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 коллекция элементов управления уже была создана формой, поэтому она работает нормально)