2015-07-25 10 views
6

Comprendo che l'acquisizione delle variabili viene eseguita dal compilatore e non dalle classi nello stesso framework .NET. Tuttavia, quando è stata introdotta la DLR, alcuni di questi lavori devono aver sicuramente dovuto essere eseguiti all'interno del framework in modo da posticiparlo al runtime.Qual è il codice che crea le variabili/chiusure catturate?

Per esempio, nel pezzo di codice indicato di seguito:

dynamic d = ... 

Func<int, bool> func = n => n > d; 

La risoluzione tipo della variabile d e la sua verifica che è un numero intero deve essere fatto in fase di esecuzione. E dal momento che d è una variabile nel metodo di contenimento della lambda, verrà catturata in una chiusura. Questa parte verrà sicuramente eseguita in fase di esecuzione.

Quindi, deduco ci deve essere una parte dei gruppi DLR (System.Core.dll principalmente) che fa questa parte.

Ho cercato e ho potuto trovare alcune classi che sembrano sospettosamente riprovevoli per questo tipo di attività. In particolare, ExpressionQuoter (nonostante il suo aspetto, questa classe non cita espressioni lambda come fa il metodo Expression.Quote), HoistedLocals e VariableBinder.

Ho pensato di invitare qualcuno che sa meglio rispondere a questo.

Quale classe o parte del framework .NET trasforma i locals che contengono metodi di lambdas (o metodi anonimi) in quelle classi separate che hanno variabili statiche che li rappresentano?

risposta

0

E poiché d è una variabile nel metodo contenente del lambda, verrà catturata in una chiusura.

d non deve essere catturato perché il lambda non lo sta utilizzando. Se il compilatore C# sceglie di acquisirlo (che non è vietato dalla regola as-if) non sarà accessibile in alcun modo.

Credo che func(d) sia eseguito come qualsiasi chiamata di metodo con un argomento dinamico.

Diamo un'occhiata a:

dynamic d = ...; //maybe "1" 

Func<bool> func = (() => d == "1234"); 

Penso che questo sia più nello spirito di ciò che si vuole sapere (Aggiornamento: infatti appena modificato la questione di avere questo modello). Il lambda dipende da d ora che non era il caso prima.

Qui, d viene catturato nella classe di chiusura generata come un campo di tipo object. dynamic viene sempre compilato come object (potenzialmente con un attributo personalizzato su di esso). Il corpo del codice lambda procede quindi a utilizzare le operazioni dinamiche standard.

Poiché tutti i riferimenti variabili in C# sono associati staticamente a una particolare variabile, non è mai necessario acquisire un numero dinamico di campi o qualcosa del genere. I campi da catturare sono noti staticamente.

+0

Ci scusiamo per questo errore prima. Stavo correggendo il mio frammento di codice dopo che hai commentato per la prima volta la domanda. –

+0

Nessun problema. Questo risponde alla domanda? – usr

+0

Sì, signore. Lo fa. Ho dimenticato che la dinamica è un segnaposto per oggetto per quanto riguarda il compilatore. Grazie. –

2

Quale classe o di una parte del framework .NET gira i locali che sono contenente metodi di lambda (o metodi anonimi) in quelle classi separate che hanno variabili statiche che li rappresentano?

No, è il compilatore che fa il lavoro.

Come passare i valori delle variabili al metodo separato? L'unico modo per farlo è definire una nuova classe di supporto che definisce anche un campo per ogni valore che si desidera passare al codice di richiamata . Inoltre, il codice di richiamata dovrebbe essere definito come come metodo di istanza in questa classe helper. Quindi, UsingLocalVariablesInTheCallbackCodemethod dovrebbe costruire un'istanza della classe helper, inizializzare i campi dai valori in sue variabili locali e quindi costruire l'oggetto delegatobound su metodo helper object/instance.

questo è molto noioso e soggetto a errori di lavoro, e, naturalmente, il compilatore C# fa tutto questo per voi automaticamente

Dal libro CLR Via C#

con il codice, ci è una classe generata che assomiglia a:

class SomeClass 
{ 
    public dynamic d; 
    public bool yourCallBack(int n) 
    { 
     return n > d; 
    } 
} 

e il codice è compilato in qualcosa tipo:

dynamic d = ... 
SomeClass class1= new SomeClass(); 
class1.d = d; 
Func<int, bool> func = class1.yourCallBack; 

C'è anche una nota per quanto riguarda la durata delle variabili catturati:

Quando un'espressione lambda fa sì che il compilatore di generare una classe con parametro/variabili locali trasformati in campi, la vita del oggetti a cui si riferiscono le variabili sono allungati. In genere, un parametro/variabile locale esce dall'ambito dell'ultimo utilizzo della variabile all'interno di un metodo. Tuttavia, trasformando la variabile in un campo , il campo mantiene l'oggetto a cui si riferisce in modo attivo per l'intera durata dell'oggetto dell'oggetto che contiene il campo. Questo non è un grosso affare nella maggior parte delle applicazioni, ma è qualcosa che si dovrebbe essere a conoscenza di .

+0

Credo che Jeffrey stia parlando del modo in cui il compilatore genera la stessa cosa. Fino al C# 3.0, il compilatore era l'unico posto che aveva questa trasformazione.Dal C# 4, credo che avessero motivo di spostare molto di ciò che il compilatore fa nel DLR in modo da supportare l'associazione di runtime delle operazioni sul tipo dinamico. –

+1

Grazie per tutto questo. Mi manca davvero il punto della mia domanda, però. Stai spiegando come funzionano le chiusure, che non è una mia domanda. –

Problemi correlati