Mik*_*kis 21 c# compiler-construction
如果您忘记初始化私有或内部的只读成员,或者声明它的类是内部的,那么C#编译器就足以为您提供"永远不会分配字段"警告.但如果该类是公开的,并且只读成员是公共的,受保护的或内部保护的,那么就没有警告!
有谁知道为什么?
示例代码,用于说明发出警告的条件以及未发出警告的条件:
namespace Test1
{
class Test1
{
#if TRY_IT
public readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
protected readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
internal readonly int o; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
private readonly int p; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
protected internal readonly int q; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
Test1()
{
if( p != 0 ) //To avoid warning 'The field is never used'
return;
}
#endif
}
public class Test2
{
#if TRY_IT
private readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
internal readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0
Test2()
{
if( m != 0 ) //To avoid warning 'The field is never used'
return;
}
#endif
public readonly int o; //Blooper: no warning about field never assigned to.
protected readonly int p; //Blooper: no warning about field never assigned to.
protected internal readonly int q; //Blooper: no warning about field never assigned to.
}
public sealed class Test3
{
public readonly int m; //Blooper: no warning about field never assigned to.
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:您可能会认为编译器在公共成员和受保护成员的情况下不会发出警告,因为期望派生类可能初始化该字段是合理的.由于多种原因,这个理论并没有任何用水:
内部类可以是子类,但编译器在这种情况下不会发出警告.
即使在密封类的情况下,编译器也无法发出警告,如示例代码中的Test3所示.
无论派生类可能做什么或不做什么,该警告对于基类的完整性都是有意义的.
语言明确禁止类初始化基类的只读成员.(谢谢,Jim Mischel.)
编辑2:如果我的记忆力很好,Java会在所有情况下提供所有正确的警告,无论未初始化的最终成员是公共的,受保护的还是私有的,并且无论包含它的类是公共的还是仅在其包中可见.
Eri*_*ert 25
简短的回答:这是编译器的疏忽.
更长的答案:启发式决定了为已声明和从未使用过的成员和本地人发出的警告,或者写入,从未阅读,阅读和从不写入的成员,都不考虑该领域的只读权限.正如您所记录的那样,它可能会在更多情况下发出警告.我们可以说,未在任何ctor中初始化的公共只读字段"将始终具有其默认值".
我会在新的一年里向Neal提及它,我们会看看我们是否可以在Roslyn中改进这些启发式方法.
顺便提一下,在许多情况下可以发出这种警告(不管是否为只读),但我们不这样做.今天我没有在我的办公室,所以我没有我的所有这些方便的情况列表中,但我只想说有很多人.它就像"字段被声明为公共字段并且在内部类的公共嵌套类中".在那种情况下,该领域实际上是内部的,我们可以做警告,但有时我们不这样做.
很多年前的一天,我改变了启发式方法,以便每个可以静态知道未被使用的字段产生警告,并且当该更改进入我们用于编译写入的类库的C#编译器的内部版本时在C#中,一切都崩溃了.这些家伙总是在编写"警告错误"的情况下开始编码,然后突然他们开始在故意初始化或通过反射和其他动态技术使用的各种字段上收到警告.我以一种主要方式破坏了构建.现在,有人可能会说,嘿,这些人应该修复他们的代码,以便它抑制警告(我确实认为),但最终结果更容易将警告启发式支持到其先前的级别.我应该逐渐做出改变.