Perché non posso modificare un metodo che contiene un metodo anonimo nel debugger?

Quindi, ogni volta che ho scritto un’espressione lambda o un metodo anonimo all’interno di un metodo che non ho capito bene, sono costretto a ricompilare e riavviare l’intera applicazione o framework di test unitario per correggerlo. Questo è molto fastidioso e alla fine perderò più tempo di quello che ho risparmiato usando questi costrutti in primo luogo. È così brutto che cerco di stare lontano da loro se posso, anche se Linq e Lambdas sono tra le mie caratteristiche C # preferite.

Suppongo che ci sia una buona ragione tecnica per cui è così, e forse qualcuno lo sa? Inoltre, qualcuno sa se verrà risolto in VS2010?

Grazie.

Sì, c’è una buona ragione per cui non puoi farlo. La semplice ragione è il costo. Il costo di abilitare questa funzione in C # (o VB) è estremamente alto.

La modifica di una funzione lambda è un caso specifico di una class di problemi ENC che sono molto difficili da risolvere con l’attuale architettura ENC (Edit’n’Continue). Vale a dire, è molto difficile ENC qualsiasi metodo in cui l’ENC esegue una delle seguenti operazioni:

  1. Genera metadati sotto forma di class
  2. Modifica o genera un metodo generico

Il primo problema è più di un vincolo logico, ma si scontra anche con un paio di limitazioni nell’architettura ENC. Vale a dire il problema sta generando la prima class non è terribilmente difficile. Ciò che è fastidioso è generare la class dopo la seconda modifica. Il motore ENC deve iniziare a tracciare la tabella dei simboli non solo per il codice live, ma anche per le classi generate. Normalmente non è così male, ma diventa sempre più difficile quando la forma di una class generata si basa sul contesto in cui viene utilizzata (come nel caso di lambda a causa delle chiusure). Ancora più importante, come si risolvono le differenze rispetto alle istanze delle classi che sono già attive nel processo?

Il secondo problema è una rigorosa limitazione nell’architettura CLR ENC. Non c’è nulla che C # (o VB) possa fare per aggirare questo problema.

Sfortunatamente Lambdas ha colpito entrambi questi problemi. La versione breve è che ENC’ing a lambda comporta molte mutazioni su classi esistenti (che potrebbero essere o non essere state generate da altre ENC). Il grosso problema è la risoluzione delle differenze tra il nuovo codice e le istanze di chiusura esistenti attive nello spazio del processo corrente. Inoltre, i lambda tendono ad usare i generici molto più di altri codici e colpiscono il numero 2.

I dettagli sono piuttosto pelosi e un po ‘troppo coinvolti per una normale risposta SO. Ho pensato di scrivere un lungo post sul blog sull’argomento. Se ci riesco, lo collegherò a questa particolare risposta.

In base a un elenco di Modifiche ai codici supportate , non è ansible aggiungere campi a tipi esistenti. I metodi anonimi sono compilati in classi con <>_c__DisplayClass1 (kinda <>_c__DisplayClass1 ), che sono precisamente questo: tipi. Anche se le tue modifiche al metodo anonimo potrebbero non includere la modifica dell’insieme di variabili incluse (aggiungendo quelle che potrebbero alterare i campi di una class esistente), suppongo che sia la ragione per cui è imansible modificare i metodi anonimi.

È un peccato che questa funzione sia parzialmente supportata in VB ma non in C #: http://msdn.microsoft.com/en-us/library/bb385795.aspx

L’implementazione dello stesso comportamento in C # ridurrebbe il livello del dolore dell’80% per le funzioni che contengono espressioni lambda, in cui non è necessario modificare le espressioni lambda né alcuna espressione che dipende da esse, e probabilmente non per un “costo mostro”.

Il riavvio di un test unitario dovrebbe richiedere una manciata di secondi, se così fosse. Non mi è mai piaciuto il modello “modifica e continua” per essere onesti – dovresti sempre rieseguire da zero IMO, nel caso in cui la modifica a metà dell’esecuzione avrebbe influito sul codice eseguito in precedenza. Detto questo, è meglio usare i test unitari che possono essere eseguiti con un rapido turnaround. Se i test delle singole unità richiedono un tempo insopportabile per iniziare, è una cosa che dovresti considerare come risposta.

EDIT: Per quanto riguarda il motivo per cui non funziona – potresti scoprire che funziona per alcuni lambda ma non per altri. Le espressioni Lambda che non catturano alcuna variabile (inclusa this ) vengono memorizzate nella cache in una variabile statica privata, in modo che venga creata solo un’istanza del delegato. Cambiare il codice significa reinizializzare quella variabile che potrebbe avere effetti collaterali interessanti che sospetto.