Есть ли действительно правильный путь кода, где эта функция не будет возвращать значение? - PullRequest
0 голосов
/ 06 апреля 2019

У меня есть функция ниже, которая перебирает список работников, вызывая их метод DoStuff ().Если первый работник выходит из строя, я пробую следующий, пока у меня не останется работников.Если все они терпят неудачу, я перебрасываю последнее исключение.

// workers is an IList<>.
public object TryDoStuff()
{
    for (int i = 0; i < workers.Count; i++)
    {
        try
        {
            return worker[i].DoStuff();
        }
        catch
        {
            if (i == workers.Count - 1)
            {
                throw; // This preserves the stack trace
            }
            else
            {
                continue; // Try the next worker
            }
        }
    }
}

При компиляции я получаю ошибку, что «не все пути кода возвращают значение» для этой функции.Хотя я могу замять ошибку, добавив явный возврат после цикла for, я сомневаюсь, что компилятор здесь точен, так как не вижу, как цикл for будет экранирован без возврата или повторного выброса исключения.И если исключение выдается повторно, допустимо не возвращать значение.

Чего мне не хватает?Csc не может определить условия в блоке catch?

Ответы [ 3 ]

2 голосов
/ 06 апреля 2019

Как упоминалось ранее, если рабочие пустые (счетчик равен 0), верный путь возврата отсутствует.

Существует также другое условие гонки (очевидно, в зависимости от полного контекста), где workers не пусто, исключение выдается для элемента, все еще есть элементы для итерации в workers, , но после вычисления if (i == workers.Count - 1) и до выполнения оператора continue, другой поток удаляетэлементы из workers (или изменяет всю переменную workers на новый экземпляр).

В этом сценарии условие for неожиданно вернет false на следующей итерации, и вы выйдете изцикл без оператора возврата для метода.

public object TryDoStuff()
{
    for (int i = 0; i < workers.Count; i++)
    {
        try
        {
            return worker[i].DoStuff();
        }
        catch
        {
            if (i == workers.Count - 1)
            {
                throw; // This preserves the stack trace
            }
            else
            {
                // XXX If workers is changed by another thread here. XXX
                continue; // Try the next worker
            }
        }
    }
}
2 голосов
/ 06 апреля 2019

Да

  1. Если в последнем индексе сгенерировано исключение, и число не соответствует ожидаемому (маловероятно, но возможно)

  2. Или, как указано RAM , если Count равно нулю

В этом случае статический анализ и последующая ошибка компилятора очень оправданы

1 голос
/ 06 апреля 2019

Я написал для вас комментарий:

Что произойдет, если число элементов списка работников будет ноль ?

Похоже, это вопрос компилятора, и он больше не исследует ваш код!:)

На самом деле этой причины достаточно для того, чтобы компилятор показал вам нижнюю ошибку

не все пути кода возвращают значение

Когда компилятор сталкивается с циклом во всем теле метода, он предполагает, что условие цикла приводит к тому, что тело цикла игнорируется, тогда он ожидал также любое значение вне цикла.

Да, даже если мы устанавливаем условие цикла так, чтобы цикл выполнялся!

Доказательство:

С ошибкой:

public static object TryDoStuff()
{
    var result =0;
    for (int i = 0; i < 3; i++)
    {
            Console.WriteLine("Add 100 unit");
            result += 100;
            return result;
    }   

    //Console.WriteLine("last line");
//  return result;
}

Без ошибок:

public static object TryDoStuff()
{
    var result =0;
    for (int i = 0; i < 3; i++)
    {
            Console.WriteLine("Add 100 unit");
            result += 100;
            // return result; you can un-comment this line too
    }   

    Console.WriteLine("last line");
    return result;
}
...