{"record":{"id":"bc1895abfefcd721","repo":"dotnet/efcore","slug":"unary-node-with-non-null-method","errorCode":null,"errorMessage":"Unary node with non-null method","messagePattern":"Unary node with non-null method","errorType":"exception","errorClass":"NotImplementedException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs","lineNumber":2478,"sourceCode":"            ExpressionType.TypeEqual\n                => BinaryExpression(SyntaxKind.EqualsExpression, visitedExpression, TypeOfExpression(Generate(node.TypeOperand))),\n\n            _ => throw new ArgumentOutOfRangeException()\n        };\n\n        return node;\n    }\n\n    /// <inheritdoc />\n    protected override Expression VisitUnary(UnaryExpression unary)\n    {\n        if (unary.Method is not null\n            && !unary.Method.IsHideBySig\n            && !unary.Method.IsSpecialName\n            && unary.Method.Name != \"op_Implicit\"\n            && unary.Method.Name != \"op_Explicit\")\n        {\n            throw new NotImplementedException(\"Unary node with non-null method\");\n        }\n\n        using var _ = ChangeContext(ExpressionContext.Expression);\n\n        var operand = Translate<ExpressionSyntax>(unary.Operand);\n\n        // TODO: Confirm what to do with the checked expression types\n\n        Result = unary.NodeType switch\n        {\n            ExpressionType.Negate => _g.NegateExpression(operand),\n            ExpressionType.NegateChecked => _g.NegateExpression(operand),\n            ExpressionType.Not when unary.Type == typeof(bool) => _g.LogicalNotExpression(operand),\n            ExpressionType.Not => _g.BitwiseNotExpression(operand),\n            ExpressionType.OnesComplement => _g.BitwiseNotExpression(operand),\n            ExpressionType.IsFalse => _g.LogicalNotExpression(operand),\n            ExpressionType.IsTrue => operand,\n            ExpressionType.ArrayLength => _g.MemberAccessExpression(operand, \"Length\"),","sourceCodeStart":2460,"sourceCodeEnd":2496,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs#L2460-L2496","documentation":"Thrown by VisitUnary when a UnaryExpression has a non-null Method that is not a conversion operator (op_Implicit/op_Explicit) and is neither HideBySig nor SpecialName. The translator only knows how to render built-in unary operators and user-defined conversions; any other method-backed unary operation (e.g. a custom overloaded unary operator that does not fit the recognised shapes) is unimplemented and throws NotImplementedException.","triggerScenarios":"An expression tree contains a UnaryExpression whose Method is a custom operator MethodInfo that is not op_Implicit/op_Explicit, not HideBySig, and not SpecialName, and the tree is translated to C#.","commonSituations":"User-defined unary operators surfaced as method-backed UnaryExpressions; expression trees built by tools that attach arbitrary MethodInfo objects to unary nodes; rare custom operator overloads in value converters or computed selectors.","solutions":["Avoid using custom method-backed unary operators in expressions handed to the C# translator.","Replace the operator call with an equivalent built-in unary expression or a method call expression.","If it is a conversion, ensure the method is named op_Implicit or op_Explicit so it is recognised."],"exampleFix":"// before: custom unary operator with Method set to a non-conversion MethodInfo\n// after: express the operation as a method call or built-in unary node without a custom Method","handlingStrategy":"validation","validationCode":"// Reject unary nodes with unsupported backing methods\nstatic bool HasUnsupportedUnaryMethod(Expression e)\n{\n    bool bad = false;\n    ExpressionVisitor visitor = null!;\n    visitor = new ExpressionVisitorWrapper {\n        OnUnary = u => { if (u.Method is not null && u.Method.Name is not (\"op_Implicit\" or \"op_Explicit\") && !u.Method.IsSpecialName) bad = true; }\n    };\n    visitor.Visit(e);\n    return bad;\n}","typeGuard":"static bool IsTranslatableUnary(UnaryExpression u) => u.Method is null || u.Method.Name is \"op_Implicit\" or \"op_Explicit\" || u.Method.IsSpecialName || u.Method.IsHideBySig;","tryCatchPattern":"try { var csharp = translator.Translate(expr); }\ncatch (NotImplementedException ex) when (ex.Message.Contains(\"Unary node with non-null method\"))\n{ throw new InvalidOperationException(\"A unary node carries an unsupported operator method.\", ex); }","preventionTips":["Avoid custom operator MethodInfos on unary nodes in translated trees.","Express non-conversion operators as method calls instead.","Keep conversion operators named op_Implicit/op_Explicit."],"tags":["expression-trees","precompiled-queries","compiled-model","linq","unary-operator"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}