dotnet/efcore · error · NotImplementedException

Private static field assignment

Error message

Private static field assignment

What it means

Thrown by LinqToCSharpSyntaxTranslator.TranslateNonPublicMemberAssignment when assigning to a non-public member whose MemberExpression.Expression is null — i.e. assigning to a private/internal static field or property. The UnsafeAccessor translation path covers instance writes only; static private writes are unimplemented.

Solutions

  1. Expose a public static setter or a method that performs the assignment, and call that from the expression tree.
  2. Move the mutable state to an instance so the static-write path is not needed.
  3. If the static is effectively a constant after startup, inject it as a constant instead of writing to it.

Example fix

// before — assigns to a private static field via reflection
var field = typeof(Config).GetField("s_value",
    BindingFlags.NonPublic | BindingFlags.Static)!;
var assign = Expression.Assign(
    Expression.Field(null, field),
    Expression.Constant(42));

// after — expose a public static setter and call it
public static void SetValue(int v) => s_value = v;
var assign = Expression.Call(
    typeof(Config), nameof(Config.SetValue), null,
    Expression.Constant(42));
Defensive patterns

Strategy: validation

Validate before calling

// Reject assignments to non-public static members.
using System.Linq.Expressions;
using System.Reflection;

bool AssignsToPrivateStatic(Expression e)
{
    bool bad = false;
    new AssignChecker(assign =>
    {
        if (assign.Left is MemberExpression { Expression: null, Member: var m })
        {
            var pub = m switch
            {
                FieldInfo f => f.IsPublic,
                PropertyInfo p => p.SetMethod?.IsPublic ?? false,
                _ => false,
            };
            if (!pub) bad = true;
        }
    }).Visit(e);
    return bad;
}

class AssignChecker(Action<BinaryExpression> onAssign) : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression b)
    { if (b.NodeType == ExpressionType.Assign) onAssign(b); return base.VisitBinary(b); }
}

Prevention

When it happens

Trigger: An expression tree assigns to a private/internal static field or static property setter through a MemberExpression with a null target (Expression.Assign(Expression.Field(null, fieldInfo), value)).

Common situations: Code that mutates private static state (configuration flags, caches) via reflection-built expression trees; provider/test fixtures that wire internal statics through Expression.Assign.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/2512f1147c0fea22. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:1708

                _g.IdentifierName(unsafeAccessorDeclaration.Identifier.Text),
                Translate<ExpressionSyntax>(memberExpression.Expression));
    }

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    protected virtual void TranslateNonPublicMemberAssignment(
        MemberExpression memberExpression,
        Expression value,
        SyntaxKind assignmentKind)
    {
        // LINQ expression trees can directly access private members, but C# code cannot. Use the .NET [UnsafeAccessor] feature.
        if (memberExpression.Expression is null)
        {
            throw new NotImplementedException("Private static field assignment");
        }

        // Get an unsafe accessor for this field/property (this internally caches and adds it to the output list of unsafe accessors)

        // [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Name>k__BackingField")]
        // static extern ref int UnsafeAccessor_Foo_Name(Foo f);
        var unsafeAccessorDeclaration = GetUnsafeAccessorDeclaration(
            memberExpression.Member is PropertyInfo propertyInfo
                ? propertyInfo.SetMethod ?? throw new UnreachableException("Attempting to assign to property without setter")
                : memberExpression.Member,
            forWrite: true);

        // The unsafe accessor declaration has been created; invoke it.
        Result = memberExpression.Member switch
        {
            FieldInfo => AssignmentExpression(
                assignmentKind,
                (ExpressionSyntax)_g.InvocationExpression(

View on GitHub (pinned to 3a2006ef56)