{"record":{"id":"741120ffcddad771","repo":"dotnet/reactive","slug":"argumentnullexception-conversion","errorCode":null,"errorMessage":"ArgumentNullException: conversion","messagePattern":"ArgumentNullException: conversion","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.Events.cs","lineNumber":73,"sourceCode":"        }\n\n        /// <summary>\n        /// Converts a typed event, conforming to the standard event pattern, to an observable sequence.\n        /// </summary>\n        /// <typeparam name=\"TDelegate\">The delegate type of the event to be converted.</typeparam>\n        /// <typeparam name=\"TSender\">The type of the sender that raises the event.</typeparam>\n        /// <typeparam name=\"TResult\">The type of the event data generated by the event.</typeparam>\n        /// <param name=\"conversion\">A function used to convert the given event handler to a delegate compatible with the underlying typed event. The resulting delegate is used in calls to the addHandler and removeHandler action parameters.</param>\n        /// <param name=\"addHandler\">Action that attaches the given event handler to the underlying .NET event.</param>\n        /// <param name=\"removeHandler\">Action that detaches the given event handler from the underlying .NET event.</param>\n        /// <returns>The observable sequence that contains data representations of invocations of the underlying typed event.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"conversion\"/> or <paramref name=\"addHandler\"/> or <paramref name=\"removeHandler\"/> is null.</exception>\n        /// <seealso cref=\"ToEventPattern\"/>\n        public static IObservable<EventPattern<TSender, TResult>> FromEventPattern<TDelegate, TSender, TResult>(Func<TypedEventHandler<TSender, TResult>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler)\n        {\n            if (conversion == null)\n            {\n                throw new ArgumentNullException(nameof(conversion));\n            }\n\n            if (addHandler == null)\n            {\n                throw new ArgumentNullException(nameof(addHandler));\n            }\n\n            if (removeHandler == null)\n            {\n                throw new ArgumentNullException(nameof(removeHandler));\n            }\n\n            return Observable.Create<EventPattern<TSender, TResult>>(observer =>\n            {\n                var h = conversion(new TypedEventHandler<TSender, TResult>((sender, args) =>\n                {\n                    observer.OnNext(new EventPattern<TSender, TResult>(sender, args));\n                }));","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/WindowsObservable.Events.cs#L55-L91","documentation":"FromEventPattern<TDelegate, TSender, TResult>(Func<TypedEventHandler<TSender, TResult>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler) supports custom event-handler delegate types. It validates in order and throws ArgumentNullException(\"conversion\") when the conversion function is null. The conversion maps the internal TypedEventHandler to the event's native delegate type and is essential for subscribe/unsubscribe.","triggerScenarios":"Calling the three-generic overload with conversion == null, e.g. FromEventPattern<RoutedEventHandler, S, R>(null, add, remove), or supplying a conversion variable that wasn't initialized.","commonSituations":"Generic helper methods forwarding a conversion parameter that callers pass as null; attempts to use the simple overload's pattern with a delegate type that requires explicit conversion; ported code from .NET event idioms where conversion was considered optional.","solutions":["Supply a real conversion, e.g. h => new SomeEventHandler(h) (or a lambda matching the delegate's signature).","If the delegate matches TypedEventHandler exactly, use the simpler two-delegate overload and avoid conversion entirely.","In generic wrappers, validate the conversion argument before forwarding to Rx and throw a caller-specific error."],"exampleFix":"// before\nObservable.FromEventPattern<EventHandler, Sender, Result>(\n    null, // throws\n    h => src.Ev += h,\n    h => src.Ev -= h);\n// after\nObservable.FromEventPattern<EventHandler, Sender, Result>(\n    h => (Sender s, Result r) => h(s, r) is implicit — supply explicit:\n    h => new EventHandler((s, r) => h(s, r)),\n    h => src.Ev += h,\n    h => src.Ev -= h);","handlingStrategy":"validation","validationCode":"if (conversion == null)\n    throw new InvalidOperationException(\"conversion delegate required for custom event handler types\");\nif (addHandler == null || removeHandler == null)\n    throw new InvalidOperationException(\"add/remove handlers required\");","typeGuard":"bool ValidConversion<TD, TS, TR>(Func<TypedEventHandler<TS, TR>, TD>? c) => c is not null;","tryCatchPattern":"try { obs = Observable.FromEventPattern<TDelegate, TSender, TResult>(conv, add, remove); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"conversion\") { log.Error(\"conversion missing; use simple overload or provide factory for delegate type\"); }","preventionTips":["Use the simpler FromEventPattern overload when the event uses TypedEventHandler directly","In generic helpers, validate the conversion parameter before forwarding","Write the conversion as an explicit lambda so its nullability is visible to the compiler and nullable analysis"],"tags":["rx","null-argument","windows-runtime","events"],"backgroundTag":"null-argument","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"}