Il codice qui sotto è C # valido - senza la cerimonia - testato su LinqPad:
Func<int, Func<int, int>> getAdder = (p) =>
new Func<int, int> ((n) => n + p);
Func<int, int> addFive = getAdder(5);
Console.WriteLine(addFive(7)); // prints 12
Mentre è vero che il C # è (solitamente) compilato JIT, questo frammento non richiede la generazione del codice in fase di runtime, solo al momento della compilazione. Il codice creerà invece classi anonime nascoste per contenere i metodi.
Il compilatore creerà la seguente struttura (supponendo che il metodo con il codice precedente sia Main
):
[System.Runtime.CompilerServices.CompilerGenerated]
private sealed class adderClass
{
public int p;
internal int adderMethod(int n)
{
return n + this.p;
}
}
[System.Runtime.CompilerServices.CompilerGenerated]
[Serializable]
private sealed class getAdderClass
{
public static readonly getAdderClass Instance;
static getAdderClass()
{
Instance = new getAdderClass();
}
internal Func<int, int> getAdderMethod(int p)
{
return new Func<int, int>(new adderClass{p = p}.adderMethod);
}
}
public void Main()
{
var getAdderFunc = new Func<int, Func<int, int>>(getAdderClass.Instance.getAdderMethod);
var adderFunc = getAdderFunc(5);
Console.WriteLine(adderFunc (7)); // prints 12
}
Il codice precedente è stato anche testato su LinqPad. Ho aggiunto i nomi delle classi e dei membri a scopo illustrativo. Il compilatore userà nomi come <>c__DisplayClass0_0
che non possono essere prodotti dal codice normale.
Come per Func
, l'implementazione usa un riferimento all'oggetto di destinazione e un puntatore al metodo, quel puntatore non può essere ottenuto con il normale C #, invece Func
e altri tipi di delegate
forniscono un'astrazione sicura .
Voglio ribadire che la trasformazione presentata sopra avviene in fase di compilazione, non in fase di runtime.
Informazioni sull'utilità dei tipi delegate
, sono come funzionano gli eventi in .NET .