Il problema fondamentale con "void" è che non significa la stessa cosa di qualsiasi altro tipo restituito. "vuoto" significa "se questo metodo ritorna, allora non restituisce alcun valore". Non nullo; null è un valore. Non restituisce alcun valore.
Questo incasina davvero il sistema dei tipi. Un sistema di tipi è essenzialmente un sistema per fare deduzioni logiche su quali operazioni sono valide su valori particolari; un metodo di ritorno vuoto non restituisce un valore, quindi la domanda "quali operazioni sono valide su questa cosa?" non ha alcun senso. Non c'è "cosa" perché ci sia un'operazione su, valida o non valida.
Inoltre, questo incasina il runtime qualcosa di feroce. Il runtime .NET è un'implementazione del Virtual Execution System, specificato come stack machine. Cioè, una macchina virtuale in cui le operazioni sono tutte caratterizzate in termini di effetto su uno stack di valutazione. (Naturalmente in pratica la macchina verrà implementata su una macchina con stack e registri, ma il sistema di esecuzione virtuale assume solo una pila.) L'effetto di una chiamata a un metodo vuoto è fondamentalmentediverso dall'effetto di una chiamata a un metodo non vuoto; un metodo non vuoto mette sempre qualcosa in pila, che potrebbe essere necessario schioccare. Un metodo vuoto non mette mai qualcosa in pila. E quindi il compilatore non può trattare i metodi void e non void allo stesso modo nel caso in cui il valore restituito dal metodo venga ignorato; se il metodo è nullo, non vi è alcun valore restituito, quindi non deve esserci alcun pop.
Per tutti questi motivi, "void" non è un tipo che può essere istanziato; non ha valori , questo è tutto. Non è convertibile in oggetto, e un metodo di ritorno del vuoto non potrà mai, mai essere trattato polimorficamente con un metodo di ritorno del vuoto, perché corrompe lo stack!
Pertanto, il vuoto non può essere usato come argomento di tipo, il che è un peccato, come si nota. Sarebbe molto conveniente.
Con il senno di poi, sarebbe stato meglio per tutti gli interessati se invece di nulla, un metodo di ritorno del vuoto restituisse automaticamente "Unità", un magico tipo di riferimento singleton. Sapresti quindi che ogni chiamata di metodo mette qualcosa nello stack , sapresti che ogni chiamata di metodo restituisce qualcosa che potrebbe essere assegnato a una variabile di tipo oggetto e, naturalmente, Unità potrebbe essere usata come argomento di tipo , quindi ci sarebbe non è necessario disporre di tipi di delegato Action e Func separati. Purtroppo, non è questo il mondo in cui ci troviamo.
Per qualche altro pensiero in questa vena vedi: