Visual Studio esegue il debug dello strumento “quick watch” e delle espressioni lambda

Perché non posso utilizzare le espressioni lambda durante il debug nella finestra “Quick watch”?

UPD: vedi anche

http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx

http://blogs.msdn.com/b/jaredpar/archive/2010/06/02/why-is-linq-absent-from-debugger-windows-part-2.aspx

Le espressioni lambda, come i metodi anonimi, sono in realtà bestie molto complesse. Anche se escludiamo Expression (.NET 3.5), questo lascia ancora molta complessità, non ultimo il fatto di essere variabili catturate, che fondamentalmente ri-strutturano il codice che le usa (ciò che si pensa come variabili diventano campi nelle classi generate dal compilatore ), con un po ‘di fumo e specchi.

In quanto tale, non mi sorprende affatto che non si possano usare pigramente – c’è un sacco di lavoro sul compilatore (e la generazione del tipo dietro le quinte) che supporta questa magia.

No, non puoi usare espressioni lambda nell’orologio / gente del posto / finestra immediata. Come Marc ha sottolineato, questo è incredibilmente complesso. Volevo approfondire ulteriormente l’argomento.

Ciò che la maggior parte delle persone non considera nell’esecuzione di una funzione anonima nel debugger è che non si verifica in un vuoto. L’atto stesso di definire ed eseguire una funzione anonima cambia la struttura sottostante della base di codice. Cambiare il codice, in generale, e in particolare dalla finestra immediata, è un compito molto difficile.

Considera il seguente codice.

 void Example() { var v1 = 42; var v2 = 56; Func func1 = () => v1; System.Diagnostics.Debugger.Break(); var v3 = v1 + v2; } 

Questo particolare codice crea una singola chiusura per acquisire il valore v1. L’acquisizione della chiusura è richiesta ogni volta che una funzione anonima utilizza una variabile dichiarata al di fuori del suo ambito. Per tutti gli effetti v1 non esiste più in questa funzione. L’ultima riga sembra in realtà più simile alla seguente

 var v3 = closure1.v1 + v2; 

Se la funzione Example viene eseguita nel debugger, si fermerà nella riga Break. Ora immagina se l’utente ha digitato quanto segue nella finestra di controllo

 (Func)(() => v2); 

Per eseguire correttamente questo debugger (o più appropriato l’EE) dovrebbe creare una chiusura per la variabile v2. Questo è difficile ma non imansible da fare.

Ciò che rende davvero un lavoro difficile per l’EE è l’ultima battuta. Come dovrebbe essere eseguita quella linea? A tutti gli effetti, la funzione anonima ha cancellato la variabile v2 e l’ha sostituita con closure2.v2. Quindi l’ultima riga di codice ora ha bisogno di essere letta

 var v3 = closure1.v1 + closure2.v2; 

Tuttavia, per ottenere effettivamente questo effetto nel codice, l’EE deve modificare l’ultima riga di codice che è in realtà un’azione ENC. Mentre questo esempio specifico è ansible, una buona parte degli scenari non lo sono.

Ciò che è ancora peggio è che l’esecuzione di un’espressione lambda non dovrebbe creare una nuova chiusura. Dovrebbe in realtà aggiungere dati alla chiusura originale. A questo punto vai dritto nei limiti ENC.

Il mio piccolo esempio purtroppo sfiora solo la superficie dei problemi in cui ci imbattiamo. Continuo a dire che scriverò un post completo su questo argomento e spero di avere tempo per questo fine settimana.

Non è ansible utilizzare le espressioni lambda nelle windows Immediate o Watch.

È comunque ansible utilizzare le espressioni System.Linq.Dynamic , che assumono il formato .Where (“Id = @ 0”, 2) – non ha l’intera gamma di metodi disponibili in Linq standard e non ha il completo potere delle espressioni lambda, ma ancora, è meglio di niente!

Il futuro è arrivato!

Il supporto per il debug di espressioni lambda è stato aggiunto a Visual Studio 2015 ( Anteprima al momento della scrittura).

Expression Evaluator ha dovuto essere riscritto, quindi mancano molte funzionalità: debug remoto di ASP.NET, dichiarazione di variabili nella finestra Immediata, controllo di variabili dinamiche, ecc. Anche le espressioni lambda che richiedono chiamate a funzioni native non sono attualmente supportate.

questo potrebbe aiutare: Finestra Immediata estesa per Visual Studio (usa Linq, Lambda Expr in Debug)

Tutto il meglio, Patrick

Le espressioni Lambda non sono supportate dal valutatore di espressioni del debugger … il che non sorprende poiché in fase di compilazione sono utilizzate per creare metodi (o Expression Trees) piuttosto che espressioni (date un’occhiata a Reflector con il display commutato su .NET 2 a guardali).

Inoltre, naturalmente, potrebbero formare una chiusura, un altro intero strato di struttura.

In VS 2015 puoi farlo ora, questa è una delle nuove funzionalità che hanno aggiunto.

Se è ancora necessario utilizzare Visual Studio 2013, è ansible scrivere un loop o un’espressione lambda nella finestra immediata utilizzando anche la finestra della console del gestore pacchetti. Nel mio caso, ho aggiunto un elenco nella parte superiore della funzione:

 private void RemoveRoleHierarchy() { #if DEBUG var departments = _unitOfWork.DepartmentRepository.GetAll().ToList(); var roleHierarchies = _unitOfWork.RoleHierarchyRepository.GetAll().ToList(); #endif try { //RoleHierarchy foreach (SchoolBo.RoleHierarchy item in _listSoRoleHierarchy.Where(r => r.BusinessKeyMatched == false)) _unitOfWork.RoleHierarchyRepository.Remove(item.Id); _unitOfWork.Save(); } catch (Exception e) { Debug.WriteLine(e.ToString()); throw; } } 

Dove la mia funzione GetAll() è:

 private DbSet _dbSet; public virtual IList GetAll() { List list; IQueryable dbQuery = _dbSet; list = dbQuery .ToList(); return list; } 

Qui ho continuato a ricevere il seguente errore, quindi volevo stampare tutti gli elementi nei vari repository:

InnerException {“L’istruzione DELETE è in conflitto con il vincolo REFERENCE \” FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ “. Il conflitto si è verificato nel database \” CC_Portal_SchoolObjectModel \ “, tabella \” dbo.Department \ “, colonna ‘OranizationalRoleId’. \ R \ nLa l’istruzione è stata chiusa. “} System.Exception {System.Data.SqlClient.SqlException}

Quindi, scopro quanti record ci sono nel repository di dipartimento eseguendo questo nella finestra immediata:

 _unitOfWork.DepartmentRepository.GetAll().ToList().Count 

Che ha restituito 243.

Quindi, se si esegue quanto segue nella console del gestore pacchetti, stampa tutti gli elementi:

 PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i } 

L’autore per l’idea può essere trovato qui

Per rispondere alla tua domanda, ecco la spiegazione ufficiale del responsabile del programma Visual Studio del motivo per cui non puoi farlo. In breve, perché “è davvero, davvero difficile” implementare in VS. Ma la funzione è attualmente in corso (come aggiornata ad agosto 2014).

Consentire la valutazione delle espressioni lambda durante il debug

Aggiungi il tuo voto mentre sei lì!