dotnet/efcore · error · NotImplementedException
Private static field access
Error message
Private static field access
What it means
Thrown by LinqToCSharpSyntaxTranslator.TranslateNonPublicMemberAccess when a MemberExpression for a non-public member has a null Expression — i.e. the member is being accessed statically (memberExpression.Expression is null). The [UnsafeAccessor]-based pattern only handles instance access; private static field/property read is not implemented.
Solutions
- Avoid reading private static fields/properties through expression trees destined for this translator; expose the value via a public static accessor and reference that instead.
- If the value is constant, compute it out-of-band and inject it as a ConstantExpression.
- Restructure so the access is on an instance rather than static (pass the holder object into the lambda).
Example fix
// before — reads a private static field via reflection-built MemberExpression
var field = typeof(Config).GetField("s_value",
BindingFlags.NonPublic | BindingFlags.Static)!;
var access = Expression.Field(null, field); // null target => static
// after — expose a public static accessor and reference it
public static int Value => s_value;
var access = Expression.Property(null, nameof(Config.Value)); Defensive patterns
Strategy: validation
Validate before calling
// Reject MemberExpressions that target non-public static members.
using System.Linq.Expressions;
using System.Reflection;
bool TargetsPrivateStaticMember(Expression e)
{
bool bad = false;
new MemberChecker(m =>
{
if (m.Expression is null && m.Member is not null)
{
var accessibility = m.Member switch
{
FieldInfo f => f.Attributes,
PropertyInfo p => p.GetMethod?.Attributes ?? MethodAttributes.Private,
_ => MethodAttributes.Private,
};
if (!accessibility.HasFlag(MethodAttributes.Public)) bad = true;
}
}).Visit(e);
return bad;
}
class MemberChecker(Action<MemberExpression> onMember) : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression m) { onMember(m); return base.VisitMember(m); }
} Prevention
- Expose static state through public accessors; do not read private statics via expression trees.
- Replace reads of private static fields with constants when the value does not change.
- Pre-scan the tree for static-typed MemberExpressions whose members are non-public.
When it happens
Trigger: An expression tree contains a MemberExpression referencing a private/internal static field or a private static property's getter with no object instance, and that member reaches the non-public member access path of the translator.
Common situations: Manually-constructed expression trees that read private static state (singletons, caches) for compiled-query source generation; provider extensions that wrap internal static fields; reflective helpers that surface static private members as MemberExpression.
Related errors
- Private static field assignment
- Compound assignment of private property not yet supported
- Anonymous type creation without members
- Can't translate method
- BinaryExpression with
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/7ab816353f46bc3e.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:1674
Result = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, IdentifierName(member.Member.Name));
break;
}
return member;
}
/// <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 TranslateNonPublicMemberAccess(MemberExpression memberExpression)
{
if (memberExpression.Expression is null)
{
throw new NotImplementedException("Private static field access");
}
// 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.GetMethod ?? throw new UnreachableException("Attempting to read from property without getter")
: memberExpression.Member,
forWrite: false);
// The unsafe accessor declaration has been created; invoke it.
Result =
_g.InvocationExpression(
_g.IdentifierName(unsafeAccessorDeclaration.Identifier.Text),
Translate<ExpressionSyntax>(memberExpression.Expression));
}View on GitHub (pinned to 3a2006ef56)