{"record":{"id":"36f8c9cc66ffcf89","repo":"dotnet/reactive","slug":"strings-linq-event-pattern-requires-two-parameters","errorCode":null,"errorMessage":"Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS","messagePattern":"Strings_Linq\\.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs","lineNumber":77,"sourceCode":"            {\n                isWinRT = true;\n\n                var pet = psr[0];\n                if (IsWinRTEventRegistrationTokenType(pet.ParameterType))\n                {\n                    throw new InvalidOperationException(Strings_Linq.EVENT_WINRT_REMOVE_METHOD_SHOULD_TAKE_ERT);\n                }\n            }\n\n            delegateType = psa[0].ParameterType;\n\n            var invokeMethod = delegateType.GetMethod(\"Invoke\")!; // NB: Delegates always have an Invoke method.\n\n            var parameters = invokeMethod.GetParameters();\n\n            if (parameters.Length != 2)\n            {\n                throw new InvalidOperationException(Strings_Linq.EVENT_PATTERN_REQUIRES_TWO_PARAMETERS);\n            }\n\n            if (!typeof(TSender).IsAssignableFrom(parameters[0].ParameterType))\n            {\n                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_SENDER_NOT_ASSIGNABLE, typeof(TSender).FullName));\n            }\n\n            if (!typeof(TEventArgs).IsAssignableFrom(parameters[1].ParameterType))\n            {\n                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.EVENT_ARGS_NOT_ASSIGNABLE, typeof(TEventArgs).FullName));\n            }\n\n            if (invokeMethod.ReturnType != typeof(void))\n            {\n                throw new InvalidOperationException(Strings_Linq.EVENT_MUST_RETURN_VOID);\n            }\n        }\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Internal/ReflectionUtils.cs#L59-L95","documentation":"The delegate behind the event must follow the .NET event pattern: two parameters (sender, eventArgs). Rx's FromEventPattern projects events into (TSender, TEventArgs) pairs, so a delegate's Invoke method with a parameter count other than 2 cannot be adapted. GetEventMethods throws InvalidOperationException when this invariant fails.","triggerScenarios":"Calling FromEventPattern<TSender, TEventArgs> with an event whose delegate type (or the delegate of the add method's parameter) has an Invoke method taking 0, 1, or 3+ parameters.","commonSituations":"Using delegates like Action or custom single-arg delegates (e.g. Action<string> callbacks) as 'events'; passing the wrong event name so reflection resolves an unrelated delegate; migrating code to FromEvent (delegate-based) when FromEventPattern (sender/args) was assumed.","solutions":["Use a delegate type conforming to the event pattern, e.g. EventHandler<TEventArgs> or a custom delegate with (object sender, TEventArgs e).","If the event really passes only a payload, use Observable.FromEvent instead of FromEventPattern.","Check that the event name string passed to FromEventPattern resolves to the intended event."],"exampleFix":"// before\npublic event Action<int> Tick;\n// after\npublic event EventHandler<int> Tick;","handlingStrategy":"validation","validationCode":"var invoke = delegateType.GetMethod(\"Invoke\");\nif (invoke == null || invoke.GetParameters().Length != 2)\n    throw new ArgumentException(\"Delegate must follow (object sender, TEventArgs e) pattern\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var src = Observable.FromEventPattern<TSender, TEventArgs>(target, eventName);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"two parameters\"))\n{\n    var src2 = Observable.FromEvent<Action<TPayload>, TPayload>(h => h.Invoke, h => target.Event += h, h => target.Event -= h);\n}","preventionTips":["Define events with EventHandler<TEventArgs> or matching (sender, args) delegates.","Use Observable.FromEvent (not FromEventPattern) for non-pattern delegates.","Check the delegate signature before choosing the operator."],"tags":["events","delegates","reflection"],"backgroundTag":"invalid-argument-format","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}