Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I NOT get warnings about uninitialized readonly fields?

Tags:

The C# compiler is kind enough to give you a "field is never assigned to" warning if you forget to initialize a readonly member which is private or internal, or if the class in which it is being declared is internal. But if the class is public, and the readonly member is public, protected or protected internal, then no warning for you!

Does anyone know why?

Sample code which demonstrates the conditions under which the warning is issued, and the conditions under which the warning is not issued:

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

EDIT: For a moment you might think that the compiler refrains from issuing the warning in the case of public and protected members because it is reasonable to expect that derived classes might initialize the field. This theory does not hold any water for a number of reasons:

  • An internal class may be subclassed, but the compiler does not refrain from issuing the warning in that case.

  • The compiler fails to issue the warning even in the case of a sealed class, as Test3 in the sample code demonstrates.

  • The warning makes sense for the sake of the integrity of the base class regardless of what a derived class may or may not do.

  • A class is expressly prohibited by the language from initializing a readonly member of a base class. (Thanks, Jim Mischel.)

EDIT2: If my memory serves me well, Java gives all the proper warnings in all cases, regardless of whether the uninitialized final member is public, protected or private, and regardless of whether the class containing it is public or visible only within its package.

like image 720
Mike Nakis Avatar asked Dec 31 '11 12:12

Mike Nakis


People also ask

Why do we need read only in C#?

In a field declaration, readonly indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class. A readonly field can be assigned and reassigned multiple times within the field declaration and constructor.

How do you declare a readonly variable in C#?

In C#, you can use a readonly keyword to declare a readonly variable. This readonly keyword shows that you can assign the variable only when you declare a variable or in a constructor of the same class in which it is declared.

Can we assign value to readonly?

You can assign a value to a ReadOnly variable only in its declaration or in the constructor of a class or structure in which it is defined.

What does private readonly mean?

If it's private and readonly , the benefit is that you can't inadvertently change it from another part of that class after it is initialized. The readonly modifier ensures the field can only be given a value during its initialization or in its class constructor.


2 Answers

The short answer: this is an oversight in the compiler.

The longer answer: the heuristic which determines what warnings to issue for members and locals that are declared and never used, or written and never read, or read and never written, does not take the read-only-ness of the field into consideration. As you correctly note, it could, and thereby issue warnings in more cases. We could say that a public readonly field that is not initialized in any ctor "will always have its default value" for example.

I'll mention it to Neal in the new year and we'll see if we can improve those heuristics in Roslyn.

Incidentally, there are a number of situations in which a warning of this sort could be issued (regardless of read-only-ness) but we do not do so. I am not in my office today so I don't have my list of all those situations handy, but suffice to say there are a lot of them. It was stuff like "the field is declared as public and is in a public nested class of an internal class". In that situation the field is effectively internal and we can do the warning, but sometimes we do not.

One day many years ago I changed the heuristic so that every field that could be statically known to be unused produced a warning, and when that change made it into the internal version of the C# compiler that we use to compile the class libraries that are written in C#, all hell broke loose. Those guys always compile with "warnings as errors" turned on, and suddenly they started getting warnings on all kinds of fields that were deliberately initialized or used onl via reflection, and other dynamic techniques. I broke the build in a major way. Now, one might argue that hey, these guys should fix their code so that it suppresses the warning (and I did argue that) but ultimately it turned out to be easier to back the warning heuristic off to its previous level. I should have made the change more gradually.

like image 138
Eric Lippert Avatar answered Oct 22 '22 05:10

Eric Lippert


This is MSDN Documentation: Compiler Warning (level 4) CS0649:

Field 'field' is never assigned to, and will always have its default value 'value'

The compiler detected an uninitialized private or internal field declaration that is never assigned a value.

So, for non-internal and non-private fields you shouldn't expect to have a warning.

But I think the main reason is that C# compiler believes that you should initialize all the things that are accessible just from your assembly. I guess C# compiler left it to the others to initialize non-private and non internal fields in their assembly.

But I tested protected internal and I don't know why C# compiler doesn't warn about it.

like image 33
Saeed Amiri Avatar answered Oct 22 '22 06:10

Saeed Amiri