Я тестировал шаблоны списков в .NET 7 и C#. Я использую Linqpad 7 и .NET 7.0.1. Шаблоны списков, я думаю, полезны для сравнения последовательностей и их интересно тестировать. Отбрасывание '_' здесь означает игнорирование числа в заданной позиции, а диапазон '..' здесь соответствует чему-либо между заданным набором значений и одним индексом, а затем заданным значением в более высоком индексе с произвольными значениями между ними.
Но в одном из примеров говорится, что вы можете захватывать переменные внутри шаблонов списков. Я не могу заставить его работать, я получаю ошибку компилятора.
Я получаю сообщение об ошибке CS0165 «Использование неназначенной локальной переменной», когда пытаюсь получить доступ к захваченным переменным. Я попытался проверить код сбоя также внутри VsCode, все еще получая ошибку, однако, если я отлаживаю внутри Linqpad, я вижу, что захваченные переменные получили значения, по крайней мере.
var someOddNumbers = new int[] { 1, 3, 5, 7, 9, 11 };
bool resultX = someOddNumbers is [1, 3, _, _, _, 11];
resultX.Dump("The 'someOddNumbers' equals a sequence of numbers 1,3,then three arbitrary numbers, then 11?");
bool isOdd = someOddNumbers is [1, .., 9, 11];
isOdd.Dump("The 'someOddNumbers' equals a sequence of numbers 1, some arbitrary numbers, then ending with 9 and 11?");
result = input is [var firstOddNumber,.. , var lastOddNumber];
if (result)
{
Console.WriteLine($"The captured variables are: {firstOddNumber} and {lastOddNumber}"); //this lines gives the CS0165 error
}
Если я закомментирую блок if, я смогу запустить пример кода, и в отладчике я увижу, что firstOddNumber и lastOddNumber устанавливаются в значение во время выполнения. Но компилятор C# 11, похоже, считает, что это недопустимый код, поскольку он использует неинициализированную переменную.
Я ожидал, что не получу ошибку компилятора и смогу также захватить переменные, определенные в шаблоне списка. Я не могу понять использование таких переменных, если я не могу их использовать. Я понимаю, что эти переменные могут быть не захвачены, если шаблон списка не совпадает, но даже при проверке наличия совпадения я получил ошибку компиляции. Однако я могу запустить код, просто не обращаясь к переменным.
Обновлять: Запятая отсутствовала перед lastOddNumber, как упомянул Гуру Строн из моего кода. И использование шаблона списка внутри условия if заставило код работать.
var someOddNumbers = new int[] { 1, 3, 5, 7, 9, 11 };
bool resultX = someOddNumbers is [1, 3, _, _, _, 11];
resultX.Dump("The 'someOddNumbers' equals a sequence of numbers 1,3,then three arbitrary numbers, then 11?");
bool isOdd = someOddNumbers is [1, .., 9, 11];
isOdd.Dump("The 'someOddNumbers' equals a sequence of numbers 1, some arbitrary numbers, then ending with 9 and 11?");
if (someOddNumbers is [var firstOddNumber, .. , var lastOddNumber]){
Console.WriteLine($"The captured variables are: {firstOddNumber} and {lastOddNumber}");
}
Кажется, что компилятор на данный момент недостаточно умен, чтобы определить, что result
является результатом совпадения и не изменяется (или существует много крайних случаев для реализации такой проверки). Встраивание переменной должно привести к компиляции кода:
if (input is [var firstOddNumber,.. var lastOddNumber])
{
Console.WriteLine($"The captured variables are: {firstOddNumber} and {lastOddNumber}");
}
Небольшое примечание:
.. var lastOddNumber
соответствует остальной части массива, а не последнему элементу, возможно, вы искали is [var firstOddNumber, .., var lastOddNumber]
(т.е. добавьте запятую после ..
).
УПД
Такое же поведение можно найти при «обычном» сопоставлении с образцом:
string? message = "This is not the null string";
if (message is {} m)
{
Console.WriteLine(m); // compiles
}
var test = message is {} m1;
if (test)
{
Console.WriteLine(m1); // error CS0165: Use of unassigned local variable 'm1'
}
На самом деле это известная проблема, заключающаяся в том, что компилятор не распространяет определенное состояние присваивания - см. это и/или это.
Демо .
Избегание использования логического флага, но использование его непосредственно внутри предложения if заставило его скомпилироваться. if (someOddNumbers is [var firstOddNumber, .. , var lastOddNumber]){ Console.WriteLine($"Захваченные переменные: {firstOddNumber} и {lastOddNumber}"); }