如何使用struct删除编译器错误:"使用未分配的局部变量"

Ada*_*dam 0 c# mono struct

C#编译器有点......老式......并且不会进行静态分析.所以它打破了看似正确的代码,如下所示:

MyStruct s;
bool inited = false;
foreach( Something foo in ACollection )
{
  if( foo.Test() )
    continue;
  if( inited )
    s.DoSomething();
  else
  {
    s = foo.GetMeAnS();
    inited = true;
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:不寻常的问题是"s"是一个结构.如果它是一个类,我只是将它初始化为null.这个结构没有有意义的"uninited"状态,我不想支付启动我立即丢弃的东西的性能成本,只是为了满足弱编译器.

代码(应该)完全正确:在s被引入之前不可能访问s.(我从实际代码中复制/粘贴,但为了简单起见,编辑了很长的方法名称).

Mono中的C#编译器曾经允许这样做,但现在却没有.除了编译器之外什么都没有改变,编译器现在给出了未赋值变量的错误.

是否有代码方式告诉它闭嘴并介意自己的业务?:)我不想改变编译器设置(如果可能),因为代码是由其他人/组织编译的 - 我更喜欢修复问题的代码方式.

Jon*_*eet 10

是否有代码方式告诉它闭嘴并介意自己的业务?

编译器的业务正在实现C#规范.您编写的代码不应该根据C#规范进行编译.该s.DoSomething()呼叫不可达s被明确赋值,因此你的代码被打破了.这不是编译器的错.如果Mono编译器曾经允许它,那么这个bug显然已经修复了.

修复它的最简单方法是明确赋值,当然:

MyStruct s = new MyStruct(); // Value will never actually be used
Run Code Online (Sandbox Code Playgroud)

在很多情况下,我们(作为人类)可以告诉某些事情永远不会发生,但编译器却不能.这是另一个例子:

public int Foo(int input)
{
    if (input >= 0)
    {
        return input;
    }
    else if (input < 0)
    {
        return -input;
    }
    // This is still reachable...
}
Run Code Online (Sandbox Code Playgroud)

我们知道每个int输入都会进入其中一个if主体,但是编译器仍会(正确地)对上面的代码给出编译错误,因为结束括号是可以访问的并且它是一个非void方法.

您声称"代码(应该)完全正确"是根据您的推理而不是C#规范...而编译器只是为了关心后者.

有一点需要注意:规范甚至不关心我们inited在某些情况下确实设置为true的事实.即使它总是具有值false,它仍然只是一个局部变量,而不是一个常量表达式.这是一个简单的例子,证明没有循环:

static void Main()
{
    int x;
    bool condition = false;
    if (condition)
    {
        Console.WriteLine(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

这仍然会出错:"错误CS0165:使用未分配的局部变量'x'"

从C#5规范的第8.7.1节:

if如果if语句可以访问且布尔表达式没有常量值,则可以访问语句的第一个嵌入语句false.

这里的表达式是condition一个局部变量.局部变量在技​​术术语中不是常量表达式,即使它永远不会改变.如果你让一个局部常量,相反,它编译:

static void Main()
{
    int x;
    const bool condition = false;
    if (condition)
    {
        Console.WriteLine(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在有关于声明正文无法访问的警告if - 但没有错误.

  • @TimSchmelter您的示例struct没有任何字段,因此无法取消初始化.添加一个字段,它将无法编译. (2认同)