{"record":{"id":"cd86d8ef300adb57","repo":"dotnet/reactive","slug":"addhandler","errorCode":null,"errorMessage":"addHandler","messagePattern":"addHandler","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs","lineNumber":17,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT License.\n// See the LICENSE file in the project root for more information. \n\nusing System.Reactive.Concurrency;\nusing System.Reactive.Disposables;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace System.Reactive.Linq\n{\n    public partial class AsyncObservable\n    {\n        public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler)\n        {\n            if (addHandler == null)\n                throw new ArgumentNullException(nameof(addHandler));\n            if (removeHandler == null)\n                throw new ArgumentNullException(nameof(removeHandler));\n\n            return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, GetSchedulerForCurrentContext());\n        }\n\n        public static IAsyncObservable<TEventArgs> FromEvent<TEventArgs>(Action<Action<TEventArgs>> addHandler, Action<Action<TEventArgs>> removeHandler, IAsyncScheduler scheduler)\n        {\n            if (addHandler == null)\n                throw new ArgumentNullException(nameof(addHandler));\n            if (removeHandler == null)\n                throw new ArgumentNullException(nameof(removeHandler));\n            if (scheduler == null)\n                throw new ArgumentNullException(nameof(scheduler));\n\n            return FromEventCore<Action<TEventArgs>, TEventArgs>(h => h, addHandler, removeHandler, scheduler);\n        }\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/FromEvent.cs#L1-L35","documentation":"The non-generic, non-converting FromEvent<TEventArgs>(addHandler, removeHandler) in FromEvent.cs null-checks addHandler first. It throws ArgumentNullException with parameter name 'addHandler' when the subscription action is null. addHandler attaches an Action<TEventArgs> to the underlying event; without it the operator cannot subscribe, so it fails fast before returning the observable.","triggerScenarios":"Calling AsyncObservable.FromEvent<TEventArgs>(addHandler, removeHandler) with addHandler == null; FromEvent.cs:17 is that `throw new ArgumentNullException(nameof(addHandler))`.","commonSituations":"Wrapping classic events like button.Click where the add lambda was omitted; passing a nullable delegate field not yet assigned; generic helper that takes add/remove and receives null from its caller.","solutions":["Pass h => source.Event += h as addHandler.","Ensure the argument is produced before the FromEvent call, not lazily.","Use the conversion-based overloads when the handler type needs adapting.","Add a unit test asserting non-null arguments when building event wrappers."],"exampleFix":"// before\nvar obs = AsyncObservable.FromEvent<EventArgs>(null, h => obj.MyEvent -= h);\n// after\nvar obs = AsyncObservable.FromEvent<EventArgs>(h => obj.MyEvent += h, h => obj.MyEvent -= h);","handlingStrategy":"validation","validationCode":"if (addHandler is null) throw new ArgumentNullException(nameof(addHandler));\nif (removeHandler is null) throw new ArgumentNullException(nameof(removeHandler));","typeGuard":"static bool Valid<TEventArgs>(Action<Action<TEventArgs>>? add, Action<Action<TEventArgs>>? remove) => add != null && remove != null;","tryCatchPattern":"try { var obs = AsyncObservable.FromEvent<EventArgs>(add, remove); } catch (ArgumentNullException ex) { log.LogError(ex, \"FromEvent requires non-null {Param}\", ex.ParamName); }","preventionTips":["Pass += and -= lambdas inline for classic events.","Null-check delegate fields before using them as handlers.","Write a small helper that enforces non-null add/remove for your event sources."],"tags":["argumentnull","fromevent","csharp","event-handlers"],"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"}