Более чистый способ включить значения NULL / по умолчанию в массивах анонимных типов? - PullRequest
3 голосов
/ 01 февраля 2020

Таким образом, этот код компилируется:

var foo = new[]
    { 
        new { prop1 = 1, prop2 = "whatever" },
        default,
        new { prop1 = 2, prop2 = "something" },
    };

Но следующее не делает:

var foo = new[]
    { 
        new { value = new { prop1 = 1, prop2 = "whatever" } },
        new { value = default },
        new { value = new { prop1 = 2, prop2 = "something" } },
    };

И до сих пор единственный способ найти его - это через :

T MakeDefaultOf<T>(T dummy) => default(T);
var foo = new[]
    { 
        new { value = new { prop1 = 1, prop2 = "whatever" } },
        new { value = MakeDefaultOf(new { prop1 = 0, prop2 = "" }) },
        new { value = new { prop1 = 2, prop2 = "something" } }
    };

Но может показаться, что для первых двух примеров у компилятора достаточно информации, чтобы определить неявный тип 'default' - так есть ли причина, по которой его нет? Есть ли способы достичь того, что я хочу, без вспомогательной функции или переменной?

Ответы [ 3 ]

2 голосов
/ 01 февраля 2020

Но, похоже, что для первых двух примеров у компилятора достаточно информации, чтобы определить неявный тип 'default' - так есть ли причина, по которой его нет?

Проблема не связана с массивом как таковым. Дело в том, что компилятор просто не позволяет инициализировать анонимный тип с нулевым значением / значением по умолчанию в соответствии с Ошибка компилятора CS0828 :

Анонимный тип не может быть инициализирован с нулевым значением или небезопасным типом, или группой методов или анонимной функцией.

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

var bar = new { value = default };   // Or new { value = null }

Теперь компилятор не может узнать тип value и, следовательно, не может определить тип bar.

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

2 голосов
/ 01 февраля 2020

Мне неизвестен какой-либо синтаксический сахар для инициализации таких значений по умолчанию.

Причиной сбоя второй (new {value = default}) инициализации является

C# массивов

Для одномерного массив, инициализатор массива должен состоять из последовательности выражений, совместимых по присваиванию с типом элемента массива.

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

В результате компилятор пытается рассуждать что такое new {value = default} и недостаточно информации для создания типа. Обратите внимание, что передача null вместо default не поможет, так как не определит конкретный тип - вспомогательный метод, который у вас есть, необходимо использовать для предоставления точного типа для null на данный момент. И результирующий тип должен быть точно таким же, как и все другие элементы массива, потому что анонимные типы должны точно совпадать, чтобы быть совместимыми с присваиванием - C# анонимные типы :

Анонимные типы типы классов, которые являются производными непосредственно от объекта и не могут быть преобразованы ни к какому типу, кроме объекта ...

... Если два или более анонимных инициализатора объекта в сборке указывают последовательность свойств, которые находятся в одном и том же Если у них одинаковые имена и типы, компилятор обрабатывает объекты как экземпляры одного типа.

2 голосов
/ 01 февраля 2020

В зависимости от вашего варианта использования, вы можете обойтись следующим:

var foo = new[]
{
    new { prop1 = 1, prop2 = "whatever" },
    default,
    new { prop1 = 2, prop2 = "something" },
}.Select(x => new { value = x } ).ToArray();
...