dotnet/reactive · error · ArgumentNullException

conversion

Error message

conversion

What it means

This FromEventPattern overload converts a TypedEventHandler to a custom delegate type and throws ArgumentNullException when the conversion function is null. The conversion is what adapts the WinRT handler to the target delegate, so it is mandatory.

Solutions

  1. Supply an explicit conversion such as h => (MyEventHandler)h if types align, or write a wrapper lambda
  2. If Delegate.CreateDelegate is used, check its result for null before calling FromEventPattern
  3. Prefer the non-conversion overload when TDelegate already is TypedEventHandler<TSender,TResult>
  4. Use a lambda wrapper instead of reflection conversion to avoid null results

Example fix

// before
Func<TypedEventHandler<Button, RoutedEventArgs>, RoutedEventHandler> conv = null;
Observable.FromEventPattern<RoutedEventHandler, Button, RoutedEventArgs>(conv, a => b.Click += a, r => b.Click -= r);
// after
Observable.FromEventPattern<RoutedEventHandler, Button, RoutedEventArgs>(
    h => new RoutedEventHandler((s, e) => h(s, e)),
    a => button.Click += a,
    r => button.Click -= r);
Defensive patterns

Strategy: validation

Validate before calling

if (conversion == null) throw new ArgumentNullException(nameof(conversion));
var converted = conversion(handler); // ensure Delegate.CreateDelegate result is checked

Type guard

static bool HasConversion<TDel, T>(Func<T, TDel> conv) => conv != null;

Try / catch

try { var obs = Observable.FromEventPattern<TDelegate, TSender, TResult>(conversion, add, remove); }
catch (ArgumentNullException ex) when (ex.ParamName == "conversion") { /* use a wrapper lambda instead */ }

Prevention

When it happens

Trigger: Calling Observable.FromEventPattern<TDelegate,TSender,TResult>(conversion, addHandler, removeHandler) with a null conversion Func, e.g. when the conversion was computed dynamically (Delegate.CreateDelegate) and returned null.

Common situations: Reflection-based delegate construction failing silently; passing null when the target delegate type already matches and the developer assumed conversion was optional.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/143344645f72a3ad. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Linq/WindowsObservable.Events.cs:70

        }

        /// <summary>
        /// Converts a typed event, conforming to the standard event pattern, to an observable sequence.
        /// </summary>
        /// <typeparam name="TDelegate">The delegate type of the event to be converted.</typeparam>
        /// <typeparam name="TSender">The type of the sender that raises the event.</typeparam>
        /// <typeparam name="TResult">The type of the event data generated by the event.</typeparam>
        /// <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>
        /// <param name="addHandler">Action that attaches the given event handler to the underlying .NET event.</param>
        /// <param name="removeHandler">Action that detaches the given event handler from the underlying .NET event.</param>
        /// <returns>The observable sequence that contains data representations of invocations of the underlying typed event.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="conversion"/> or <paramref name="addHandler"/> or <paramref name="removeHandler"/> is null.</exception>
        /// <seealso cref="ToEventPattern"/>
        public static IObservable<EventPattern<TSender, TResult>> FromEventPattern<TDelegate, TSender, TResult>(Func<TypedEventHandler<TSender, TResult>, TDelegate> conversion, Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
        {
            if (conversion == null)
            {
                throw new ArgumentNullException(nameof(conversion));
            }

            if (addHandler == null)
            {
                throw new ArgumentNullException(nameof(addHandler));
            }

            if (removeHandler == null)
            {
                throw new ArgumentNullException(nameof(removeHandler));
            }

            return Observable.Create<EventPattern<TSender, TResult>>(observer =>
            {
                var h = conversion(new TypedEventHandler<TSender, TResult>((sender, args) =>
                {
                    observer.OnNext(new EventPattern<TSender, TResult>(sender, args));
                }));

View on GitHub (pinned to 94b5d5ab91)