问题描述
C# 编译器有点......老式......并且不会进行静态分析.所以它打破了看似正确的代码,如下所示:
The C# compiler is a bit ... old fashioned ... and won't do static analysis. So it breaks on seemingly correct code like this:
MyStruct s;
bool inited = false;
foreach( Something foo in ACollection )
{
if( foo.Test() )
continue;
if( inited )
s.DoSomething();
else
{
s = foo.GetMeAnS();
inited = true;
}
}
注意:不寻常的问题是s"是一个结构体.如果它是一个类,我只需将它初始化为 null.这个结构体没有有意义的未初始化"状态,我不想为了满足弱编译器而支付初始化我立即扔掉的东西的性能成本.
代码(应该)完全正确:在 s 被初始化之前是不可能访问 s 的.(我从实际代码中复制/粘贴,但为简单起见编辑了长方法名称).
The code (should be) fully correct: it's impossible to access s until s has been inited. (I've copy/pasted from actual code, but edited-out long method names for simplicity).
Mono 中的 C# 编译器曾经允许这样做,但现在不允许了.除了编译器之外没有任何变化,它现在会在未分配的变量上出错.
C# compiler in Mono used to allow this, but now it doesn't. Nothing has changed except the compiler, which now gives an error on unassigned variable.
有没有一种代码方式可以告诉它闭嘴,管好自己的事?:) 我不想摆弄更改编译器设置(如果可能),因为代码是由其他人/组织编译的 - 我更喜欢解决问题的代码方式.
Is there a code way to tell it to shut up and mind its own business? :) I don't want to fiddle with changing compiler-settings (if possible) because the code is compiled by other people/orgs - I'd prefer a code way of fixing the problem.
推荐答案
编译器的业务是实现 C# 规范.您编写的代码不应该根据 C# 规范进行编译.s.DoSomething()
调用在没有明确分配 s
的情况下是可以访问的,因此您的代码已损坏.这不是编译器的错.如果 Mono 编译器使用允许它,那么这是一个显然现在已修复的错误.
The compiler's business is implementing the C# specification. The code you've written should not compile according to the C# specification. The s.DoSomething()
call is reachable without s
being definitely assigned, therefore your code is broken. That's not the compiler's fault. If the Mono compiler used to allow it, that was a bug which has apparently now been fixed.
修复它的最简单方法当然是明确赋值:
The simplest way of fixing it is to definitely assign the value, of course:
MyStruct s = new MyStruct(); // Value will never actually be used
在很多情况下,我们(作为人类)可以判断某事永远不会发生,但编译器却不能.这是另一个例子:
There are plenty of cases where we (as humans) can tell that something will never happen, but the compiler can't. Here's another example:
public int Foo(int input)
{
if (input >= 0)
{
return input;
}
else if (input < 0)
{
return -input;
}
// This is still reachable...
}
我们知道每个 int
输入都会进入那些 if
主体之一,但编译器仍会(正确地)给出编译上面代码有错误,因为右大括号是可达的,而且它是一个非空方法.
We know that every int
input will go into one of those if
bodies, but the compiler will still (correctly) give a compilation error on the above code, because the closing brace is reachable and it's a non-void method.
您声称代码(应该)完全正确"是根据您的推理,而不是 C# 规范……而编译器只是为了关心后者.
Your claim that "The code (should be) fully correct" is according to your reasoning, not the C# specificiation... and the compiler is only meant to care about the latter.
需要注意的一点:规范甚至不关心我们确实在某些情况下将 inited
设置为 true 的事实.即使它总是具有false
的值,它仍然只是一个局部变量,而不是一个常量表达式.这是一个简单的示例,演示了没有循环:
One thing to note: the specification doesn't even care about the fact that we do actually set inited
to true in some cases. Even if it always had the value of false
, it's still just a local variable, not a constant expression. Here's a simple example demonstrating that with no loop:
static void Main()
{
int x;
bool condition = false;
if (condition)
{
Console.WriteLine(x);
}
}
这还是报错:error CS0165: Use of unassigned local variable 'x'"
This still gives an error: "error CS0165: Use of unassigned local variable 'x'"
来自 C# 5 规范的第 8.7.1 节:
From section 8.7.1 of the C# 5 specification:
如果 if 语句可达且布尔表达式没有常量值 false
,则 if
语句的第一个嵌入语句是可达的.
这里的表达式是condition
,它是一个局部变量.局部变量不是技术术语中的常量表达式,即使它永远不会改变.如果你把它变成一个局部常量,它将编译:
Here the expression is condition
, which is a local variable. A local variable is not a constant expression in technical terms, even if it will never change. If you make it a local constant instead, it will compile:
static void Main()
{
int x;
const bool condition = false;
if (condition)
{
Console.WriteLine(x);
}
}
现在有一个关于 if
语句的主体无法访问的警告 - 但没有错误.
Now there's a warning about the body of the if
statement being unreachable - but there's no error.
这篇关于如何使用结构删除编译器错误:“使用未分配的局部变量"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!