У меня проблема с C#, дающим ошибку компиляции «Использование неназначенной локальной переменной». Что мне не хватает?
// returns generic result of a function with error message
// why the function failed
public class Result
{
public bool isSuccess = true;
public string errorMessage = string.Empty;
public static implicit operator bool(Result r)
{
return r.isSuccess;
}
public static Result operator &(Result a, Result b)
{
return !a.isSuccess ? a : b;
}
public static Result operator |(Result a, Result b)
{
if (a.isSuccess)
{
return a;
}
if (b.isSuccess)
{
return b;
}
return new Result
{
isSuccess = false,
errorMessage = $"{a.errorMessage}\nOut{b.errorMessage}"
};
}
public static bool operator false(Result a)
{
return !a.isSuccess;
}
public static bool operator true(Result a)
{
return a.isSuccess;
}
}
static Result Func1(int nIn, out int nOut)
{
nOut = nIn + 1;
return new Result();
}
private static void Main(string[] args)
{
var resultA =
Func1(0, out var a1) &&
Func1(a1, out var a2); // compiles fine
var resultB =
Func1(0, out var b1) &&
Func1(b1, out var b2) &&
Func1(b2, out var b3); // Use of unassigned local variable 'b2'
}
да, но идея состоит в том, чтобы функция терпела неудачу и не выполняла никакой дальнейшей логики, как только первый вызов терпит неудачу. Если я использую &, то все будет оцениваться до оценки конечного результата.





Я думаю, что этот мая является ошибкой в компиляторе - я лично ожидаю, что b2 будет определенно назначен там. Однако спецификация для определенного назначения довольно туманна, поэтому я не собираюсь пытаться доказать это тем или иным способом прямо сейчас. Возможно, правила недостаточно «умны», чтобы понять, что единственный способ, которым (x && y) является истинным, — это если оцениваются и x, и y, и поэтому в (x && y) && zz должна быть в состоянии полагаться на то, что и x, и y были оценивается.
Однако это довольно легко обойти, просто добавив дополнительную пару круглых скобок:
var resultB =
Func1(0, out var b1) &&
(Func1(b1, out var b2) && Func1(b2, out var b3));
Это работает, как и ожидалось, с static bool Func1(int nIn, out int nOut), так что это должно быть связано с неявными операторами.
@GSerg, да, это был мой старый шаблон, и он отлично работал.
проблема в том, что это всего лишь простой пример. У меня есть функции, которые делают гораздо больше: `var result1 = Func1(0, out var b1) && Func1(b1, out var b2) && Func1(b2, out var b3) && Func1(b3, out var b4) && Func1( b4, out вар b5) && и т. д.`
Это также работает: var resultB = (bool)Func1(0, out var b1) && Func1(b1, out var b2) && Func1(b2, out var b3);. Удаление public static Result operator & также исправляет это.
@GSerg, хотя это будет работать в этом контексте, resultB теперь будет логическим значением, а не результатом. У меня много функций рода Result DoABunchOfStuff() { return DoThingA(out resultA) && DoThingB(resultA, out resultB) && DoThingC(resultB, out resultC) & etc
@Chebz: Хотя возможно, что это работает должен, вы находитесь на территории крайних случаев между параметрами out, пользовательскими операторами и определенным назначением для нескольких выражений. Возможно, вы захотите найти альтернативный подход.
@JonSkeet Если вы удалите bool operator false, он жалуется, что он должен существовать для короткого замыкания operator&, и действительно, в присутствии bool operator false это происходит. Правила короткого замыкания четко определены, поэтому компилятор знает, что либо будут вычисляться первые два выражения, либо ему не нужно будет вычислять третье — и действительно, это то, что происходит с примитивными типами. Я предполагаю, что здесь компилятор пытается объяснить operator& ложь о своем результате, но я не понимаю, как она могла солгать, чтобы оценка продолжалась без вызова обеих функций.
@GSerg: Действительно. Вот почему я думаю, что это либо тонкая ошибка компилятора, или спецификация не пытается обрабатывать эту комбинацию функций. Я определенно согласен, что логически должен работать.
единственное, о чем я могу думать, это заранее определить параметры, например, int b1 = default; int b2 = default; int b3 = default; var resultB = Func1(0, out b1) && Func1(b1, out b2) && Func1(b2, out b3); не уверен, что это безопасно?
@Chebz: Да, это должно быть безопасно. Вы даже можете объявить их все в одном выражении: int b1 = default, b2 = default, b3 = default;
Одним из вариантов было бы использовать & вместо &&. Это не будет использовать короткое замыкание, поэтому каждое частичное выражение будет выполнено, и поэтому будет назначен каждый выходной параметр. Это не подходит для всех ситуаций, но если нет побочных эффектов, то все должно быть в порядке.