dotnet/efcore · error · NotImplementedException

Unary node with non-null method

Error message

Unary node with non-null method

What it means

VisitUnary handles standard unary operators and user-defined conversions (op_Implicit/op_Explicit). A UnaryExpression carrying an arbitrary backing Method that is not a conversion and not a special-name/hide-by-sig operator cannot be rendered, so it throws NotImplementedException.

Source

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

            ExpressionType.TypeEqual
                => BinaryExpression(SyntaxKind.EqualsExpression, visitedExpression, TypeOfExpression(Generate(node.TypeOperand))),

            _ => throw new ArgumentOutOfRangeException()
        };

        return node;
    }

    /// <inheritdoc />
    protected override Expression VisitUnary(UnaryExpression unary)
    {
        if (unary.Method is not null
            && !unary.Method.IsHideBySig
            && !unary.Method.IsSpecialName
            && unary.Method.Name != "op_Implicit"
            && unary.Method.Name != "op_Explicit")
        {
            throw new NotImplementedException("Unary node with non-null method");
        }

        using var _ = ChangeContext(ExpressionContext.Expression);

        var operand = Translate<ExpressionSyntax>(unary.Operand);

        // TODO: Confirm what to do with the checked expression types

        Result = unary.NodeType switch
        {
            ExpressionType.Negate => _g.NegateExpression(operand),
            ExpressionType.NegateChecked => _g.NegateExpression(operand),
            ExpressionType.Not when unary.Type == typeof(bool) => _g.LogicalNotExpression(operand),
            ExpressionType.Not => _g.BitwiseNotExpression(operand),
            ExpressionType.OnesComplement => _g.BitwiseNotExpression(operand),
            ExpressionType.IsFalse => _g.LogicalNotExpression(operand),
            ExpressionType.IsTrue => operand,
            ExpressionType.ArrayLength => _g.MemberAccessExpression(operand, "Length"),

View on GitHub (pinned to dbf9771522)

Solutions

  1. Use standard unary operators built by the C# compiler rather than attaching custom methods.
  2. If you have a custom conversion, implement it as op_Implicit/op_Explicit so it is recognized.
  3. Replace the custom-method unary with an explicit method call.

Example fix

// before
var u = Expression.MakeUnary(ExpressionType.Negate, operand, null, customMethodInfo);
// after
var u = Expression.Negate(operand); // standard operator, no custom method
Defensive patterns

Strategy: validation

Validate before calling

protected override Expression VisitUnary(UnaryExpression u) {
    if (u.Method is not null && !u.Method.IsSpecialName && !u.Method.IsHideBySig
        && u.Method.Name != "op_Implicit" && u.Method.Name != "op_Explicit") Found = true;
    return u;
}

Prevention

When it happens

Trigger: A UnaryExpression with a custom Method that is neither op_Implicit/op_Explicit nor an IsSpecialName/IsHideBySig operator method.

Common situations: Hand-built unary expressions with custom operator methods; unusual operator overloads attached to unary nodes.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/bc1895abfefcd721. Report an issue: GitHub.