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 # не завантажує метадані для приватних полів структур, що знаходяться у бібліотеках, на які посилаються . Ці метадані можуть бути величезними , і це сповільнить компілятор за дуже маленьку виграш, щоб кожен раз це завантажувати в пам'ять.
І тепер ви повинні мати можливість вивести причину виявленої помилки. Коли компілятор перевіряє, чи визначений параметр визначено, він порівнює кількість відомих полів з кількістю полів, які були визначені ініціалізовано, і у вашому випадку він знає лише про нульові загальнодоступні поля, оскільки метадані приватного поля не були завантажені . Компілятор робить висновок "нульові поля потрібні, нульові поля ініціалізовані, ми хороші".
Як я вже говорив, ця помилка існує вже не одне десятиліття, і такі люди, як ти, періодично перекривають її та повідомляють про неї. Це нешкідливо, і навряд чи це буде виправлено, тому що виправити це має майже нульову користь, але велика вартість продуктивності.
І звичайно, помилка не дорікає приватним полям структур, які є вихідним кодом у вашому проекті, оскільки, очевидно, компілятор вже має інформацію про приватні поля під рукою.