Использование неназначенной локальной переменной в параметре out

У меня проблема с 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'
}

Одним из вариантов было бы использовать & вместо &&. Это не будет использовать короткое замыкание, поэтому каждое частичное выражение будет выполнено, и поэтому будет назначен каждый выходной параметр. Это не подходит для всех ситуаций, но если нет побочных эффектов, то все должно быть в порядке.

John 15.05.2022 09:47

да, но идея состоит в том, чтобы функция терпела неудачу и не выполняла никакой дальнейшей логики, как только первый вызов терпит неудачу. Если я использую &, то все будет оцениваться до оценки конечного результата.

Chebz 15.05.2022 10:50
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что этот мая является ошибкой в ​​​​компиляторе - я лично ожидаю, что 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 15.05.2022 09:20

@GSerg, да, это был мой старый шаблон, и он отлично работал.

Chebz 15.05.2022 09:22

проблема в том, что это всего лишь простой пример. У меня есть функции, которые делают гораздо больше: `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) && и т. д.`

Chebz 15.05.2022 09:27

Это также работает: var resultB = (bool)Func1(0, out var b1) && Func1(b1, out var b2) && Func1(b2, out var b3);. Удаление public static Result operator & также исправляет это.

GSerg 15.05.2022 09:27

@GSerg, хотя это будет работать в этом контексте, resultB теперь будет логическим значением, а не результатом. У меня много функций рода Result DoABunchOfStuff() { return DoThingA(out resultA) && DoThingB(resultA, out resultB) && DoThingC(resultB, out resultC) & etc

Chebz 15.05.2022 09:34

@Chebz: Хотя возможно, что это работает должен, вы находитесь на территории крайних случаев между параметрами out, пользовательскими операторами и определенным назначением для нескольких выражений. Возможно, вы захотите найти альтернативный подход.

Jon Skeet 15.05.2022 09:46

@JonSkeet Если вы удалите bool operator false, он жалуется, что он должен существовать для короткого замыкания operator&, и действительно, в присутствии bool operator false это происходит. Правила короткого замыкания четко определены, поэтому компилятор знает, что либо будут вычисляться первые два выражения, либо ему не нужно будет вычислять третье — и действительно, это то, что происходит с примитивными типами. Я предполагаю, что здесь компилятор пытается объяснить operator& ложь о своем результате, но я не понимаю, как она могла солгать, чтобы оценка продолжалась без вызова обеих функций.

GSerg 15.05.2022 09:57

@GSerg: Действительно. Вот почему я думаю, что это либо тонкая ошибка компилятора, или спецификация не пытается обрабатывать эту комбинацию функций. Я определенно согласен, что логически должен работать.

Jon Skeet 15.05.2022 10:00

единственное, о чем я могу думать, это заранее определить параметры, например, int b1 = default; int b2 = default; int b3 = default; var resultB = Func1(0, out b1) && Func1(b1, out b2) && Func1(b2, out b3); не уверен, что это безопасно?

Chebz 15.05.2022 10:36

@Chebz: Да, это должно быть безопасно. Вы даже можете объявить их все в одном выражении: int b1 = default, b2 = default, b3 = default;

Jon Skeet 15.05.2022 15:52

Другие вопросы по теме