真的有一个有效的代码路径,这个函数不会 return 一个值吗?

Is there really a valid code-path where this function won't return a value?

我有以下函数,它遍历工作人员列表,调用他们的 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
            }
        }
    }
}

在编译时,我得到一个错误 "not all code paths return a value" 这个函数。虽然我可以通过在 for 循环之后添加一个显式 return 来消除错误,但我怀疑编译器在这里是否准确,因为我看不出如果没有 returning 将如何转义 for 循环或重新抛出异常。如果重新抛出异常,则 returning 值是有效的。

我错过了什么? csc 无法推理 catch 块中的条件吗?

  1. 如果在最后一个索引上抛出异常并且计数不是您期望的(不太可能但可能)

  2. 或者如 RAM 所指出的,如果 Count 为零

在这种情况下,静态分析和随后的编译错误是非常有道理的

如前所述,如果 workers 为空(计数为 0),则没有有效的 return 路径。

还有另一个竞争条件(显然取决于完整的上下文),其中 workers 不为空,在元素上抛出异常,workers 中仍有元素要迭代, but 在评估 if (i == workers.Count - 1) 之前 continue 语句执行后,另一个线程从 workers 中删除元素(或将整个 workers 变量更改为新实例)。

在那种情况下,for 条件将在下一次迭代中意外地 return 为假,并且您将退出循环,没有针对该方法的 return 语句。

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
            }
        }
    }
}

我写了一条评论给你:

What will be happen if the count of the workers list items be zero?

这似乎是编译器问题,它没有对您的代码进行更多研究! :)

实际上这个原因足以让编译器向您显示下面的错误

not all code paths return a value

当编译器在整个方法体中遇到循环时,它假定循环条件导致循环体被忽略,然后它也期望循环外的任何值。

是的,即使我们按照循环执行的方式设置循环条件!

证明:

错误:

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;
}