Preferisco più costruttori rispetto ai valori predefiniti e personalmente non mi piace il tuo esempio di due costruttori, dovrebbe essere implementato in modo diverso.
Il motivo dell'utilizzo di più costruttori è che il principale può semplicemente verificare se tutti i parametri non sono nulli e se sono validi mentre altri costruttori possono fornire valori predefiniti per quello principale.
Tuttavia, nei tuoi esempi non vi è alcuna differenza tra di loro perché anche il costruttore secondario passa un null come valore predefinito e il costruttore principale deve conoscere anche il valore predefinito. Penso che non dovrebbe.
Ciò significa che sarebbe più pulito e meglio separato se implementato in questo modo:
public DelegateCommand(Action<T> execute) : this(execute, _ => true) { }
public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
this.execute = execute ?? throw new ArgumentNullException(..);
this.canExecute = canExecute ?? throw new ArgumentNullException(..);
}
nota che _ => true è passato al costruttore principale che ora controlla anche tutti i parametri per null e non si preoccupa di alcun valore predefinito.
Il punto più importante è tuttavia l'estensibilità. Più costruttori sono più sicuri quando è possibile estendere il codice in futuro. Se aggiungi altri parametri obbligatori e quelli facoltativi devono arrivare alla fine, interromperai tutte le implementazioni correnti. Puoi rendere il vecchio costruttore [Obsolete] e informare gli utenti che verrà rimosso, dando loro il tempo di migrare alla nuova implementazione senza rompere istantaneamente il loro codice.
D'altro canto rendere troppi parametri facoltativi potrebbe confondere anche perché se alcuni di essi sono richiesti in uno scenario e facoltativi in un altro, sarà necessario studiare la documentazione invece di scegliere il giusto costruttore semplicemente guardando il suo i parametri.