99

以下代码导致使用未分配的局部变量“numberOfGroups”

int numberOfGroups;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

然而,这段代码工作正常(虽然,ReSharper说这= 10是多余的):

int numberOfGroups = 10;
if(options.NumberOfGroups == null || !int.TryParse(options.NumberOfGroups, out numberOfGroups))
{
    numberOfGroups = 10;
}

我错过了什么,还是编译器不喜欢我的||

我已将其缩小到dynamic导致问题的范围(options在我上面的代码中是一个动态变量)。问题仍然存在,为什么我不能这样做

此代码无法编译:

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        dynamic myString = args[0];

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

但是,此代码确实

internal class Program
{
    #region Static Methods

    private static void Main(string[] args)
    {
        var myString = args[0]; // var would be string

        int myInt;
        if(myString == null || !int.TryParse(myString, out myInt))
        {
            myInt = 10;
        }

        Console.WriteLine(myInt);
    }

    #endregion
}

我没有意识到dynamic这会是一个因素。

4

3 回答 3

73

我很确定这是一个编译器错误。很好的发现!

编辑:这不是一个错误,正如 Quartermeister 所展示的那样;dynamic 可能会实现一个奇怪的true运算符,这可能会导致y永远不会被初始化。

这是一个最小的复制:

class Program
{
    static bool M(out int x) 
    { 
        x = 123; 
        return true; 
    }
    static int N(dynamic d)
    {
        int y;
        if(d || M(out y))
            y = 10;
        return y; 
    }
}

我认为没有理由认为这应该是非法的;如果你用 bool 替换 dynamic 它编译就好了。

实际上我明天要与 C# 团队会面;我会跟他们提的。为错误道歉!

于 2013-04-30T17:37:44.647 回答
52

如果动态表达式的值是具有重载trueoperator的类型,则变量可能未被分配。

运算符将||调用true运算符来决定是否评估右侧,然后if语句将调用true运算符来决定是否评估其主体。对于 normal bool,这些将始终返回相同的结果,因此将评估一个,但对于用户定义的运算符,没有这样的保证!

建立在 Eric Lippert 的 repro 的基础上,这里有一个简短而完整的程序,它演示了两个路径都不会执行并且变量将具有其初始值的情况:

using System;

class Program
{
    static bool M(out int x)
    {
        x = 123;
        return true;
    }

    static int N(dynamic d)
    {
        int y = 3;
        if (d || M(out y))
            y = 10;
        return y;
    }

    static void Main(string[] args)
    {
        var result = N(new EvilBool());
        // Prints 3!
        Console.WriteLine(result);
    }
}

class EvilBool
{
    private bool value;

    public static bool operator true(EvilBool b)
    {
        // Return true the first time this is called
        // and false the second time
        b.value = !b.value;
        return b.value;
    }

    public static bool operator false(EvilBool b)
    {
        throw new NotImplementedException();
    }
}
于 2013-04-30T19:08:42.627 回答
7

来自 MSDN(重点是我的):

动态类型允许其发生的操作绕过编译时类型检查。相反,这些操作是在运行时解决的。动态类型简化了对 COM API(如 Office Automation API)的访问,以及对动态 API(如 IronPython 库)和 HTML 文档对象模型 (DOM) 的访问。

在大多数情况下,动态类型的行为类似于类型对象。但是,包含动态类型表达式的操作不会被编译器解析或类型检查。

由于编译器不进行类型检查或解析任何包含动态类型表达式的操作,因此它不能确保变量将通过使用TryParse().

于 2013-04-30T17:34:02.943 回答