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 - 但没有错误.
| 归档时间: |
|
| 查看次数: |
1390 次 |
| 最近记录: |