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.)