c# - 为什么我没有收到有关未初始化的只读字段的警告?

标签 c# compiler-construction

如果您忘记初始化一个私有(private)或内部的只读成员,或者声明它的类是内部的,C# 编译器会非常友好地给您一个“字段永远不会分配给”的警告。但是,如果类是公共(public)的,并且只读成员是公共(public)的、 protected 或内部 protected ,那么就不会向您发出警告!

有人知道为什么吗?

演示发出警告的条件和不发出警告的条件的示例代码:

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. 
    } 
} 

编辑: 有那么一刻,您可能会认为编译器不会在公共(public)和 protected 成员的情况下发出警告,因为派生类可能会初始化该字段是合理的。由于多种原因,该理论站不住脚:

  • 内部类可以被子类化,但编译器不会 在这种情况下不要发出警告。

  • 即使在密封的情况下,编译器也无法发出警告 类,如示例代码中的 Test3 所示。

  • 为了基地的完整性,警告是有道理的 类而不管派生类可以做什么或不可以做什么。

  • 语言明确禁止类初始化 基类的只读成员。 (谢谢,吉姆·米歇尔。)

EDIT2:如果我没记错的话,Java 在所有情况下都会给出所有正确的警告,无论未初始化的最终成员是公共(public)的、 protected 还是私有(private)的,也不管类是否包含它是公开的或仅在其包内可见。

最佳答案

简短的回答:这是编译器的疏忽。

较长的答案:确定向声明但从未使用过、写入但从未读取过或读取过但从未写入过的成员和局部变量发出哪些警告的启发式算法不采用字段的只读性考虑在内。正如您正确指出的那样,它可以,从而在更多情况下发出警告。例如,我们可以说未在任何 ctor 中初始化的公共(public)只读字段“将始终具有其默认值”。

我会在新的一年向 Neal 提及它,我们将看看我们是否可以在 Roslyn 中改进这些启发式方法。

顺便说一下,在很多情况下都可能会发出此类警告(无论是否为只读),但我们不会这样做。我今天不在办公室,所以手边没有所有这些情况的 list ,但足以说明其中有很多。就像“该字段被声明为公共(public)的并且位于内部类的公共(public)嵌套类中”之类的东西。在那种情况下,该场实际上是内部的,我们可以发出警告,但有时我们不会。

多年前的一天,我更改了启发式方法,以便静态已知未使用的每个字段都产生警告,当该更改进入 C# 编译器的内部版本时我们用来编译用 C# 编写的类库,一切都乱套了。那些家伙总是在编译时打开“警告作为错误”,突然间他们开始在各种故意初始化或仅通过反射和其他动态技术使用的字段上收到警告。我在很大程度上破坏了构建。现在,有人可能会争辩说,嘿,这些人应该修复他们的代码,以便它抑制警告(我确实争辩过)但最终证明将警告启发式返回到其先前级别更容易。我应该更缓慢地做出改变。

关于c# - 为什么我没有收到有关未初始化的只读字段的警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8688204/

相关文章:

c# - 表单退出时关闭 Stream Read 和 Stream Writer

c# - Serilog topshelf 集成不起作用

c# - 异步设计中的 session

compiler-construction - 使用内存数据编译文件而不是 Common Lisp 中的真实文件

PHP 执行权限被拒绝

compiler-construction - 在纯汇编中输出整数的更有效方法

java - 如何更改默认编译器?

c# - 姓氏、名字的正则表达式

c# - 如何对多键字典进行部分搜索

C#动态编译字符串和.cs文件