Я заметил странное поведение в моем коде, когда случайно закомментировал строку в функции во время проверки кода. Это было очень трудно воспроизвести, но я приведу аналогичный пример здесь.
У меня есть этот тестовый класс:
public class Test
{
public void GetOut(out EmailAddress email)
{
try
{
Foo(email);
}
catch
{
}
}
public void Foo(EmailAddress email)
{
}
}
Нет электронной почты, в GetOut
которой обычно выдается ошибка:
Выходной параметр 'email' должен быть назначен до того, как элемент управления покинет текущий метод
Однако, если EmailAddress находится в структуре в отдельной сборке, ошибка не создается, и все компилируется нормально.
public struct EmailAddress
{
#region Constructors
public EmailAddress(string email)
: this(email, string.Empty)
{
}
public EmailAddress(string email, string name)
{
this.Email = email;
this.Name = name;
}
#endregion
#region Properties
public string Email { get; private set; }
public string Name { get; private set; }
#endregion
}
Почему компилятор не предписывает, чтобы Email был назначен? Почему этот код компилируется, если структура создается в отдельной сборке, но не компилируется, если структура определена в существующей сборке?
struct Dog{}
все хорошо.Ответы:
TLDR: это известная давняя ошибка. Я впервые написал об этом в 2010 году:
https://blogs.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assignment-anomaly/
Он безвреден, и вы можете спокойно его игнорировать и поздравить себя с обнаружением несколько неясной ошибки.
О, это так, в моде. У него просто неверное представление о том, какое условие подразумевает, что переменная определенно назначена, как мы увидим.
В этом суть ошибки. Ошибка является следствием пересечения того, как компилятор C # выполняет определенную проверку присваивания для структур и как компилятор загружает метаданные из библиотек.
Учти это:
Хорошо, на данный момент, что мы знаем?
f
является псевдонимом для переменной типаFoo
, поэтому хранилище уже выделено и определенно находится в том состоянии, в котором оно вышло из распределителя хранилища. Если вызывающая сторона поместила значение в переменную, это значение есть.Что нам нужно? Мы требуем, чтобы это
f
было определенно назначено в любой точке, где контроль уходитM
нормально. Так что вы ожидаете что-то вроде:который устанавливает
f.x
иf.y
их значения по умолчанию. Но как насчет этого?Это также должно быть хорошо. Но, и вот кикер, почему мы должны назначать значения по умолчанию только для того, чтобы выбросить их через мгновение? Средство проверки определенного присваивания в C # проверяет, назначено ли каждое поле ! Это законно:
И почему это не должно быть законным? Это тип значения.
f
переменная, и она уже содержит допустимое значение типаFoo
, так что давайте просто установим поля, и все готово, верно?Правильно. Так в чем же ошибка?
Обнаруженная вами ошибка: в качестве экономии средств компилятор C # не загружает метаданные для частных полей структур, которые находятся в ссылочных библиотеках . Эти метаданные могут быть огромными , и это будет тормозить компилятор из-за очень небольшого выигрыша, чтобы каждый раз загружать все это в память.
И теперь вы сможете определить причину найденной ошибки. Когда компилятор проверяет, определен ли параметр out, он сравнивает количество известных полей с числом полей, которые были определенно инициализированы, и в вашем случае он знает только о нулевых открытых полях, поскольку метаданные закрытых полей не были загружены. , Компилятор делает вывод: «Обязательные поля равны нулю, инициализированы нулевые поля, все хорошо».
Как я уже сказал, эта ошибка существует уже более десяти лет, и такие люди, как вы, иногда заново ее обнаруживают и сообщают об этом. Он безвреден и вряд ли будет исправлен, потому что его исправление дает практически нулевую выгоду, но приводит к высокой производительности.
И, конечно, ошибка не воспроизводится для закрытых полей структур, которые находятся в исходном коде вашего проекта, потому что, очевидно, компилятор уже имеет информацию о закрытых полях под рукой.
источник
System.TimeSpan
вместо этого, ошибки приходят:error CS0269: Use of unassigned out parameter 'email'
иerror CS0177: The out parameter 'email' must be assigned to before control leaves the current method
. Существует только одно нестатическое полеTimeSpan
, а именно_ticks
. Именноinternal
на его сборку mscorlib. Эта сборка особенная? То же самоеSystem.DateTime
, и его полеprivate
Хотя это выглядит как ошибка, в этом есть какой-то смысл.
«Отсутствующая ошибка» появляется только при использовании библиотеки классов. И библиотека классов могла быть написана на другом языке .net, например, VB.Net. «Отслеживание определенных назначений» - это особенность C #, а не фреймворка.
Так что, в целом, я не думаю, что это ошибка, но я не знаю о том, как это можно утверждать.
источник
default(T)
). Таким образом, нет нарушения безопасности памяти или чего-то подобного.