PrismLibrary/Prism · error · ArgumentNullException

Resources.DelegateCommandDelegatesCannotBeNull

Error message

Resources.DelegateCommandDelegatesCannotBeNull

What it means

The generic AsyncDelegateCommand<T> validates both its execute delegate (Func<T, CancellationToken, Task>) and canExecute delegate (Func<T, bool>) for null and throws ArgumentNullException with Resources.DelegateCommandDelegatesCannotBeNull when either is null. A command must always have an execute path.

Solutions

  1. Supply non-null execute and canExecute delegates to the constructor.
  2. Initialize any backing delegate fields before command construction.
  3. Use the single-delegate constructor if only the execute method is available.

Example fix

// before
DeleteCommand = new AsyncDelegateCommand<Item>(_deleteHandler, _canDelete); // _deleteHandler null
// after
DeleteCommand = new AsyncDelegateCommand<Item>(async (item, ct) => await DeleteAsync(item, ct), item => item != null);
Defensive patterns

Strategy: validation

Validate before calling

if (executeMethod == null || canExecuteMethod == null)
    throw new InvalidOperationException("Both delegates required for AsyncDelegateCommand<T>");

Type guard

bool IsValidCommand<T>(Func<T, CancellationToken, Task> exec, Func<T, bool> canExec) => exec != null && canExec != null;

Try / catch

try { Cmd = new AsyncDelegateCommand<Item>(handler, canExec); }
catch (ArgumentNullException ex) { logger.LogError(ex, "null delegate for AsyncDelegateCommand<T>"); }

Prevention

When it happens

Trigger: new AsyncDelegateCommand<T>(null, canExecute) or new AsyncDelegateCommand<T>(execute, null) using the two-parameter constructor; passing delegates obtained via reflection or a nullable backing field that is null.

Common situations: ViewModels constructing typed commands from fields initialized later or from DI-resolved handlers that are null; refactors that changed method signatures leaving nulls.

Related errors


AI-assisted analysis of PrismLibrary/Prism@358118cd64 (2026-09-15). Data as JSON: /api/errors/c005b7928b21c4f1. Report an issue: GitHub.

Appendix: source

Thrown at src/Prism.Core/Commands/AsyncDelegateCommand{T}.cs:73

        : this((p, c) => executeMethod(p).WaitAsync(c), canExecuteMethod)
#else
        : this((p, c) => executeMethod(p), canExecuteMethod)
#endif
    {

    }

    /// <summary>
    /// Creates a new instance of <see cref="DelegateCommand"/> with the <see cref="Func{Task}"/> to invoke on execution
    /// and a <see langword="Func" /> to query for determining if the command can execute.
    /// </summary>
    /// <param name="executeMethod">The <see cref="Func{T, CancellationToken, Task}"/> to invoke when <see cref="ICommand.Execute"/> is called.</param>
    /// <param name="canExecuteMethod">The delegate to invoke when <see cref="ICommand.CanExecute"/> is called</param>
    public AsyncDelegateCommand(Func<T, CancellationToken, Task> executeMethod, Func<T, bool> canExecuteMethod)
        : base()
    {
        if (executeMethod == null || canExecuteMethod == null)
            throw new ArgumentNullException(nameof(executeMethod), Resources.DelegateCommandDelegatesCannotBeNull);

        _executeMethod = executeMethod;
        _canExecuteMethod = canExecuteMethod;
    }

    /// <summary>
    /// Gets the current state of the AsyncDelegateCommand
    /// </summary>
    public bool IsExecuting
    {
        get => _isExecuting;
        private set => SetProperty(ref _isExecuting, value, OnCanExecuteChanged);
    }

    ///<summary>
    /// Executes the command.
    ///</summary>
    public async Task Execute(T parameter, CancellationToken? cancellationToken = null)

View on GitHub (pinned to 358118cd64)