Table of Contents

VSTHRD117 Avoid initialization of ThreadStatic fields in a type initializer

A static field marked with ThreadStaticAttribute has a separate value on each thread. A field initializer or static constructor runs only on the thread that initializes the containing type, so the field has its default value on every other thread. In C#, this also applies to auto-property backing fields marked with [field: ThreadStatic].

Severity

An inline field or auto-property initializer that explicitly assigns the default value for its type, such as null, 0, or default, produces an informational diagnostic. The initializer is redundant but does not create different initial values across threads.

All other initializers and assignments reported by this rule produce a warning because they can initialize the field differently on the type-initializing thread.

Examples of patterns that are flagged by this analyzer

class Example
{
    [ThreadStatic]
    private static object value = new object();
}
class Example
{
    [ThreadStatic]
    private static object value;

    static Example()
    {
        value = new object();
    }
}
Class Example
    <ThreadStatic>
    Private Shared value As Object = New Object()
End Class
Class Example
    <ThreadStatic>
    Private Shared value As Object

    Shared Sub New()
        value = New Object()
    End Sub
End Class

Solution

Remove an initializer that assigns the default value. For other initializers or static-constructor assignments, initialize the value independently on each thread, typically by using lazy initialization at the point of use.

class Example
{
    [ThreadStatic]
    private static object value;

    private static object Value => value ??= new object();
}
Class Example
    <ThreadStatic>
    Private Shared value As Object

    Private Shared ReadOnly Property Value As Object
        Get
            If value Is Nothing Then
                value = New Object()
            End If

            Return value
        End Get
    End Property
End Class

No code fix is offered because the correct per-thread initialization depends on how the field is used.

This rule is equivalent to .NET SDK rule CA2019. When both analyzer packages are enabled, configure or suppress one of the duplicate diagnostics.