TLDR: это известная давняя ошибка. Я впервые написал об этом в 2010 году:
https://blogs.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assignment-anomaly/
Он безвреден, и вы можете спокойно его игнорировать и поздравить себя с обнаружением несколько неясной ошибки.
Почему компилятор не обеспечивает принудительно Emailназначенное значение?
О, это так, в моде. У него просто неверное представление о том, какое условие подразумевает, что переменная определенно назначена, как мы увидим.
Почему этот код компилируется, если структура создается в отдельной сборке, но не компилируется, если структура определена в существующей сборке?
В этом суть ошибки. Ошибка является следствием пересечения того, как компилятор C # выполняет определенную проверку присваивания для структур и как компилятор загружает метаданные из библиотек.
Учти это:
struct Foo
{
public int x;
public int y;
}
// Yes, public fields are bad, but this is just
// to illustrate the situation.
void M(out Foo f)
{
Хорошо, на данный момент, что мы знаем? fявляется псевдонимом для переменной типа Foo, поэтому хранилище уже выделено и определенно находится в том состоянии, в котором оно вышло из распределителя хранилища. Если вызывающая сторона поместила значение в переменную, это значение есть.
Что нам нужно? Мы требуем, чтобы это fбыло определенно назначено в любой точке, где контроль уходит Mнормально. Так что вы ожидаете что-то вроде:
void M(out Foo f)
{
f = new Foo();
}
который устанавливает f.xи f.yих значения по умолчанию. Но как насчет этого?
void M(out Foo f)
{
f = new Foo();
f.x = 123;
f.y = 456;
}
Это также должно быть хорошо. Но, и вот кикер, почему мы должны назначать значения по умолчанию только для того, чтобы выбросить их через мгновение? Средство проверки определенного присваивания в C # проверяет, назначено ли каждое поле ! Это законно:
void M(out Foo f)
{
f.x = 123;
f.y = 456;
}
И почему это не должно быть законным? Это тип значения. fпеременная, и она уже содержит допустимое значение типа Foo, так что давайте просто установим поля, и все готово, верно?
Правильно. Так в чем же ошибка?
Обнаруженная вами ошибка: в качестве экономии средств компилятор C # не загружает метаданные для частных полей структур, которые находятся в ссылочных библиотеках . Эти метаданные могут быть огромными , и это будет тормозить компилятор из-за очень небольшого выигрыша, чтобы каждый раз загружать все это в память.
И теперь вы сможете определить причину найденной ошибки. Когда компилятор проверяет, определен ли параметр out, он сравнивает количество известных полей с числом полей, которые были определенно инициализированы, и в вашем случае он знает только о нулевых открытых полях, поскольку метаданные закрытых полей не были загружены. , Компилятор делает вывод: «Обязательные поля равны нулю, инициализированы нулевые поля, все хорошо».
Как я уже сказал, эта ошибка существует уже более десяти лет, и такие люди, как вы, иногда заново ее обнаруживают и сообщают об этом. Он безвреден и вряд ли будет исправлен, потому что его исправление дает практически нулевую выгоду, но приводит к высокой производительности.
И, конечно, ошибка не воспроизводится для закрытых полей структур, которые находятся в исходном коде вашего проекта, потому что, очевидно, компилятор уже имеет информацию о закрытых полях под рукой.