{"record":{"id":"260b223236b56fd4","repo":"louthy/language-ext","slug":"invalidoperationexception-eqresolver","errorCode":null,"errorMessage":"InvalidOperationException","messagePattern":"InvalidOperationException","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"LanguageExt.Core/Traits/Resolve/EqResolver.cs","lineNumber":52,"sourceCode":"        {\n            ResolutionError = $\"Trait implementation not found for: {typeof(A).Name}\";\n            MakeDefault();\n            return;\n        }\n        \n        // Equals\n        \n        var m = Resolver.Method(impl, \"Equals\", source, source);\n        if (m is null)\n        {\n            ResolutionError = $\"`Equals` method not found for: {typeof(A).Name}\";\n            MakeDefault();\n            return;\n        }\n\n        EqualsMethod    = m;\n        EqualsMethodPtr = m.MethodHandle.GetFunctionPointer();\n        EqualsFunc      = (x, y) => (bool?)EqualsMethod.Invoke(null, [x, y]) ?? throw new InvalidOperationException();\n        \n        // GetHashCode\n        \n        m = Resolver.Method(impl, \"GetHashCode\", source);\n        if (m is null)\n        {\n            ResolutionError = $\"`GetHashCode` method not found for: {typeof(A).Name}\";\n            MakeDefault();\n            return;\n        }\n\n        GetHashCodeMethod    = m;\n        GetHashCodeMethodPtr = m.MethodHandle.GetFunctionPointer();\n        GetHashCodeFunc      = x => (int?)GetHashCodeMethod.Invoke(null, [x]) ?? throw new InvalidOperationException();\n    }\n\n    static void MakeDefault()\n    {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Traits/Resolve/EqResolver.cs#L34-L70","documentation":"EqResolver.EqResolve reflects over a type's trait implementation to find static Equals and GetHashCode methods, then wraps them in delegates using MethodInfo.Invoke. The delegate throws InvalidOperationException when the reflection Invoke returns null (the ?? branch), meaning the resolved method returned null where a bool was required — i.e. the resolved method does not have the expected signature/return semantics.","triggerScenarios":"A type's Eq<A> implementation exposes a static 'Equals(A,A)' whose invocation returns null (wrong return type, e.g. bool? or object returning null) so `(bool?)EqualsMethod.Invoke(...) ?? throw` fires when the delegate is first called.","commonSituations":"Hand-written Eq instances with subtly wrong signatures (non-static, wrong arity, boxed returns); refactoring changed the method shape while the resolver cached stale reflection metadata; AOT/trimming stripping or altering members.","solutions":["Fix the Eq<A> implementation so Equals(A,A) is a static method returning a non-null bool.","Implement the Eq trait properly (or omit it so the resolver falls back to MakeDefault/EqualityComparer<A>.Default).","Clear any cached resolver state and retry after fixing the implementation.","Check the method signature with reflection yourself: static, two A parameters, bool return."],"exampleFix":"// before\npublic static object? Equals(A x, A y) => null; // wrong signature\n// after\npublic static bool Equals(A x, A y) => x.Equals(y);","handlingStrategy":"try-catch","validationCode":"var m = typeof(EqImpl).GetMethod(\"Equals\", new[] { typeof(A), typeof(A) });\nbool ok = m is { IsStatic: true } && m.ReturnType == typeof(bool);","typeGuard":"bool IsValidEq<A>(MethodInfo? m) => m is { IsStatic: true } && m.ReturnType == typeof(bool) && m.GetParameters().Length == 2;","tryCatchPattern":"try { var eq = Eq<A>.Default; var r = eq.Equals(x, y); }\ncatch (InvalidOperationException ex) { /* fall back to EqualityComparer<A>.Default */ }","preventionTips":["Write Eq<A> Equals as a static method returning plain bool","Add tests invoking the trait equality before relying on it","Avoid nullable or object return types on trait members","Keep LanguageExt versions aligned across projects"],"tags":["reflection","equality","resolver","languageext"],"backgroundTag":"invalid-argument-value","analyzedSha":"2f0e3628242889774d4141960a35671a0280051f","analyzedAt":"2026-09-15T03:31:55.716Z","contentChangedAt":"2026-09-15T03:31:55.716Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}