Nunca declare outro delegado C♯ novamente

Caso você não saiba, nunca há necessidade de declarar delegados personalizados no código C♯.

Por meio de uma rápida revisão, delegados são indicadores de função fortemente tipados de C♯. Fechamentos, retornos de chamada e eventos são todos implementados usando delegados. A instrução delegate declara a assinatura de um ponteiro de função e dá um nome a essa assinatura. Você pode então atribuir uma variável desse tipo de delegado a um método ou função anônima cuja assinatura corresponda ao delegado.

Uma coisa irritante sobre a declaração de delegado é que é difícil saber onde colocá-la. Nós o aninhamos dentro de uma classe, como mostrado acima? Colocamos em um arquivo .cs separado ? Agrupamos várias instruções de delegado em um arquivo ou colocamos cada uma em seu próprio arquivo?

Outra desgraça dos delegados personalizados é que cada um é mais uma coisa para a qual temos que inventar um nome. A nomenclatura é freqüentemente citada como uma das coisas mais difíceis que os programadores devem fazer. Eu mesmo proferi obscenidades húngaras como delegate void VoidFormDoubleDelegate (Form form, double @double); quando um bom nome me escapou ou quando eu quis reutilizar a declaração para vários fins.

Não seria bom eliminar totalmente a instrução delegate em nossos aplicativos? Podemos.

Todos os delegados de uma determinada aridade são semelhantes e podem ser unificados por meio de genéricos. Portanto, tudo o que precisamos é uma declaração de delegado genérico para cada aridade possível.

A Microsoft forneceu essas declarações na forma dos delegados genéricos System.Action e System.Func , introduzidos já no .NET 2.0. Esses delegados genéricos acomodam procedimentos nulos, procedimentos unários, procedimentos binários, procedimentos ternários e assim por diante por meio de procedimentos 10-ários. (‘Nullary’ significa zero parâmetros; é representado pelo delegado System.Action ou pelo delegado System.Func <TResult> . Um procedimento 10-ário pode usar System.Action <T1… T10> ou System.Func <T1… T10 , TResult> .)

Talvez você precise de um delegado para uma função que tenha 11 parâmetros e um valor de retorno. Nesse caso, você precisa declarar seu próprio delegado genérico de 11 parâmetros porque a Biblioteca de Classes do .NET Framework só declara delegados genéricos até um arity de 10.

delegate TResult Func<T1,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
,
T9
,
T10
,
T11
,
TResult>(T1 arg1,
T2 arg2
,
T3 arg3
,
T4 arg4
,
T5 arg5
,
T6 arg6
,
T7 arg7
,
T8 arg8
,
T9 arg9
,
T10 arg10
,
T11 arg11
);

Se você precisar declarar um delegado de 11 parâmetros, terá problemas maiores a resolver do que a questão de onde colocar uma instrução de delegado .

(Eu adaptei este protocolo de uma postagem do blog que escrevi em maio de 2010.)