Constant or static readonly?

I use SonarQube to analyze my C# code and I like it. It even gives really good hints about things I didn’t know about C#. But there are two rules about using constant and static readonly properties and fields that I am quite confused because it seems they are in conflict with each other. Again, I will write a blog post to figure out that and learn it. This is a continuation of the previous blog post (C#: Difference of Properties and Fields).

Public constant members should not be used

This is SonarQube’s rule S2339 and its severity is even critical. Practically this means that public constant fields and properties should be static readonly and not const:

public static readonly string StaticReadonlyField = "static readonly";  // this is OK (#1)
public const string ConstField = "const";  // this is not OK (#2)

What makes #2 not OK? It is tricky pitfall which is rare but better not to use it because consequences can be fatal. That is the reason it has critical severity in SonarQube. Here is a diagram that illustrates this pitfall:

 

public-const-diagram
If only MyAssemblyA.dll is compiled, MyAssemblyB.dll will refer to the old value of MyAssembleA.Version.

In the example above MyAssemblyB.dll took the value of MyAssemblyA.Version when MyAssemblyB.dll was compiled. And after that MyAssemblyA was updated to version 2.0 and compiled, but MyAssemblyB wasn’t compiled. MyAssemblyB thought that MyAssembly.Version was still “1.0” even if its value was changed to “2.0”. Here is the reason for this:

Constant members are copied at compile time to the call sites, instead of being fetched at runtime. (SonarQube rule S2339)

So you shouldn’t use public constant members. Prefer static readonly members. Note that this doesn’t mean you can’t use private or protected constant members or constant variables. This only applies to public constant members. So prefer these:

public static string Version;  // static property which has only a getter
{
  get { return "2.0"; }
}
public static readonly string Version = "2.0";  // static readonly field

Static readonly constants should be const instead

This is SonarQube’s rule S3962. But unlike previous rule, this has only minor severity. Confusing with this rule is that it practically says just opposite than the previous rule: don’t use static readonly. Here is an example:

 public class MyExample
{
  private static readonly int x = 1; // this is not OK (#1)
  private const readonly int y = 2; // this is OK (#2)
  public static readonly double MainVersion = 1.0; // this is not OK (#3)
  public const double SubVersion = 1.1; // this is OK (#4)
} 

Reason to prefer const is performance. Because const is calculated at compile time and static readonly at runtime it makes const slightly faster. Maybe this doesn’t practically matter to your program’s performance but it is a good practice.

What then makes me confuse with this rule? It is “#3 vs #4”. The previous rule just said that #3 is OK and #4 is not OK when here it is opposite of it. What should I do if I have a public constant value? They are even quite common. Public constant fields are quite risky (remember its severity: critical) but here severity is only a minor. Maybe in the future, I will use properties instead of #3 and #4:

public static double MainVersion; // #3
{
  get { return 1.0; }
}

public static double SubVersion; // #4
{
  get { return 1.1; }
}

Conclusion

  • Don’t use public constant members
    • Instead use public static properties with getter only
  • When private or protected member or variable prefer `const` over `static readonly` because it is more efficient
public MyClass GoodConstantMembers
{
  public static string Version  // public, use static read-only
  {
    get { return "1.0"; }
  }

  private const int x = 4;  // non-public, use const

  public void MyMethod()
  {
    int const name = "xxx";  // variable, use const
    ...
  }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s