Edit

Share via


CA1810: Initialize reference type static fields inline

Property Value
Rule ID CA1810
Title Initialize reference type static fields inline
Category Performance
Fix is breaking or non-breaking Non-breaking
Enabled by default in .NET 8 No

Cause

A reference type declares an explicit static constructor.

Rule description

When a type declares an explicit static constructor, the just-in-time (JIT) compiler adds a check to each static method and instance constructor of the type to make sure that the static constructor was previously called. Static initialization is triggered when any static member is accessed or when an instance of the type is created. However, static initialization is not triggered if you declare a variable of the type but do not use it, which can be important if the initialization changes global state.

When all static data is initialized inline and an explicit static constructor is not declared, common intermediate language (CIL) compilers add the beforefieldinit flag and an implicit static constructor, which initializes the static data, to the CIL type definition. When the JIT compiler encounters the beforefieldinit flag, most of the time the static constructor checks are not added. Static initialization is guaranteed to occur at some time before any static fields are accessed but not before a static method or instance constructor is invoked. Note that static initialization can occur at any time after a variable of the type is declared.

Static constructor checks can decrease performance. Often a static constructor is used only to initialize static fields, in which case you must only make sure that static initialization occurs before the first access of a static field. The beforefieldinit behavior is appropriate for these and most other types. It is only inappropriate when static initialization affects global state and one of the following is true:

  • The effect on global state is expensive and is not required if the type is not used.

  • The global state effects can be accessed without accessing any static fields of the type.

How to fix violations

To fix a violation of this rule, initialize all static data when it is declared and remove the static constructor.

When to suppress warnings

It is safe to suppress a warning from this rule if one of the following applies:

  • Performance is not a concern.
  • Global state changes that are caused by static initialization are expensive or must be guaranteed to occur before a static method of the type is called or an instance of the type is created.

Suppress a warning

If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.

#pragma warning disable CA1810
// The code that's violating the rule is on this line.
#pragma warning restore CA1810

To disable the rule for a file, folder, or project, set its severity to none in the configuration file.

[*.{cs,vb}]
dotnet_diagnostic.CA1810.severity = none

For more information, see How to suppress code analysis warnings.

Example

The following example shows a type, StaticConstructor, that violates the rule and a type, NoStaticConstructor, that replaces the static constructor with inline initialization to satisfy the rule.

public class StaticConstructor
{
    static int someInteger;
    static string? resourceString;

    static StaticConstructor()
    {
        someInteger = 3;
        ResourceManager stringManager =
           new ResourceManager("strings", Assembly.GetExecutingAssembly());
        resourceString = stringManager.GetString("string");
    }

    public void Print()
    {
        Console.WriteLine(someInteger);
    }
}

public class NoStaticConstructor
{
    static int someInteger = 3;
    static string? resourceString = InitializeResourceString();

    static string? InitializeResourceString()
    {
        ResourceManager stringManager =
           new ResourceManager("strings", Assembly.GetExecutingAssembly());
        return stringManager.GetString("string");
    }

    public void Print()
    {
        Console.WriteLine(someInteger);
    }
}
Imports System
Imports System.Resources

Namespace ca1810

    Public Class StaticConstructor

        Shared someInteger As Integer
        Shared resourceString As String

        Shared Sub New()

            someInteger = 3
            Dim stringManager As New ResourceManager("strings",
            System.Reflection.Assembly.GetExecutingAssembly())
            resourceString = stringManager.GetString("string")

        End Sub

    End Class


    Public Class NoStaticConstructor

        Shared someInteger As Integer = 3
        Shared resourceString As String = InitializeResourceString()

        Private Shared Function InitializeResourceString()

            Dim stringManager As New ResourceManager("strings",
            System.Reflection.Assembly.GetExecutingAssembly())
            Return stringManager.GetString("string")

        End Function

    End Class

End Namespace

Note the addition of the beforefieldinit flag on the CIL definition for the NoStaticConstructor class.

.class public auto ansi StaticConstructor
extends [mscorlib]System.Object
{
} // end of class StaticConstructor

.class public auto ansi beforefieldinit NoStaticConstructor
extends [mscorlib]System.Object
{
} // end of class NoStaticConstructor