为什么我不会收到有关未初始化的只读字段的警告?

如果您忘记初始化一个只读或者私有的只读成员,或者它所声明的类是内部的,那么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. 
    } 
} 

编辑:暂时你可能会认为编译器不会在公共和受保护成员的情况下发出警告,因为期望派生类可能初始化该字段是合理的。 由于多种原因,这个理论并不成立:

  • 内部类可能会被分类,但编译器并不会在这种情况下发出警告。

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

  • 无论派生类可能做什么或不可能做什么,警告对于基类的完整性都是有意义的。

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

  • 编辑2:如果我的记忆对我很好,在任何情况下,Java都会给出所有适当的警告,不管未初始化的最终成员是公共的,保护的还是私人的,无论包含它的类是公共的还是仅在其包中都是可见的。


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

    较长的回答:启发式确定对于已声明且从未使用过的成员和本地人发出的警告,或者写入并从未读过,或从未读过或从未写过的警告,并不考虑字段的只读性。 正如您正确地指出的那样,它可以在更多情况下发出警告。 例如,我们可以说一个未在任何ctor中初始化的公共只读字段“将始终具有其默认值”。

    我会在新的一年里提及尼尔,我们会看看我们是否可以改进罗斯林的启发式。

    顺便说一句,有很多情况下可以发出这种警告(不管是否只读),但我们不这样做。 我今天不在办公室,所以我没有所有这些情况的列表,但足以说有很多这样的情况。 这就像“这个领域被宣布为公共,并且在一个内部类的公共嵌套类中”。 在这种情况下,该领域是有效的内部,我们可以做出警告,但有时我们不会。

    很多年前的一天,我改变了启发式方法,以便可以静态地知道每一个未被使用的字段都会产生一个警告,并且当这种改变使它成为我们用来编译写入的类库的内部版本的C#编译器时在C#中,所有地狱都垮了。 那些家伙总是编译时发出“警告作为错误”,突然他们开始接受有意初始化或通过反射使用的各种领域的警告,以及其他动态技术。 我主要打破了构建。 现在,有人可能会争辩说,嘿,这些人应该修正他们的代码,以便它能够抑制警告(并且我曾经辩论过),但是最终证明将警告启发式恢复到之前的级别更容易。 我应该逐渐做出改变。


    这是MSDN文档:编译器警告(级别4)CS0649:

    字段“字段”永远不会分配给,并且将始终具有其默认值“值”

    编译器检测到未初始化的私有或内部字段声明,它永远不会被赋值。

    所以,对于非内部和非私人领域,你不应该期望有警告。

    但我认为主要的原因是C#编译器认为你应该初始化所有可以从你的程序集访问的东西。 我想C#编译器会让其他人在其程序集中初始化非私有和非内部字段。

    但我测试了protected internal ,我不知道为什么C#编译器没有警告它。


    如果它是公开的(或者更好的不是私人的),它可以被你的项目之外的另一个类使用。 这对建立应该被其他人使用的图书馆很重要。 如果您对每个未使用的公共财产,领域或方法都收到警告,您将看不到真正的问题。

    链接地址: http://www.djcxy.com/p/21075.html

    上一篇: Why do I NOT get warnings about uninitialized readonly fields?

    下一篇: Why does the lock object have to be static?