Следующий код приводит к использованию неназначенной локальной переменной numberOfGroups :
int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Однако этот код работает нормально (хотя ReSharper говорит, что = 10
он избыточен):
int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
numberOfGroups = 10;
}
Мне что-то не хватает или компилятору не нравится мой ||
?
Я сузил это до dynamic
причинения проблем ( options
в моем приведенном выше коде была динамическая переменная). Остается вопрос, почему я не могу этого сделать ?
Этот код не компилируется:
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
dynamic myString = args[0];
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Однако этот код делает :
internal class Program
{
#region Static Methods
private static void Main(string[] args)
{
var myString = args[0]; // var would be string
int myInt;
if(myString == null || !int.TryParse(myString, out myInt))
{
myInt = 10;
}
Console.WriteLine(myInt);
}
#endregion
}
Я не понимал, dynamic
что это может быть фактором.
out
параметру, в качестве входных данныхout
параметру. Конечно, интересно подумать, какой вспомогательный код компилятор должен создать, чтобы избежать проблемы, или если это вообще возможно.Ответы:
Я почти уверен, что это ошибка компилятора. Хорошая находка!
Изменить: это не ошибка, как демонстрирует Quartermeister; dynamic может реализовывать странный
true
оператор, который можетy
никогда не инициализироваться.Вот минимальное воспроизведение:
Я не вижу причин, почему это должно быть незаконно; если вы замените динамический на bool, он компилируется нормально.
Я действительно встречаюсь с командой C # завтра; Я скажу им об этом. Приносим извинения за ошибку!
источник
d
может быть типа с перегруженнымtrue
оператором. Я отправил ответ с примером, в котором ни одна ветка не взята.Возможно, переменная не будет присвоена, если значение динамического выражения относится к типу с перегруженным
true
оператором .||
Оператор будет вызыватьtrue
оператор , чтобы решить , следует ли оценивать правую, а затемif
оператор будет вызыватьtrue
оператор , чтобы решить , следует ли оценивать свое тело. В нормальном режимеbool
они всегда будут возвращать один и тот же результат, поэтому будет оцениваться ровно один результат, но для пользовательского оператора такой гарантии нет!Основываясь на репро Эрика Липперта, вот короткая и полная программа, которая демонстрирует случай, когда ни один путь не будет выполнен, а переменная будет иметь свое начальное значение:
источник
d
оценивать дважды? (Я не спорю , что она ясно это , как вы показали.) Я ожидал бы оценочный результатаtrue
(от первого оператора вызова, причины по||
) , чтобы быть «прошел вдоль» вif
заявление. Это определенно произойдет, если, например, вы поместите туда вызов функции.d
оценивается только один раз, как и следовало ожидать. Этоtrue
оператор, который вызывается дважды, один раз||
и один разif
.var cond = d || M(out y); if (cond) { ... }
. Сначала мы оцениваем,d
чтобы получитьEvilBool
ссылку на объект. Чтобы оценить||
, мы сначала вызываемEvilBool.true
с этой ссылкой. Это возвращает истину, поэтому мы закорачиваем и не вызываемM
, а затем присваиваем ссылкуcond
. Затем мы переходим кif
утверждению.if
Оператор оценивает его состояние путем вызоваEvilBool.true
.Из MSDN (выделено мной):
Поскольку компилятор не проверяет типы и не разрешает какие-либо операции, содержащие выражения динамического типа, он не может гарантировать, что переменная будет назначена с помощью
TryParse()
.источник
numberGroups
присваивается (вif true
блоке), если нет, второе условие гарантирует присваивание (черезout
).myString == null
(полагаясь только наTryParse
).if
выражение) включает в себяdynamic
переменную, оно не разрешается во время компиляции (поэтому компилятор не может сделать эти предположения).