Débogage de Visual Studio Outil «Quick Watch» et expressions lambda

Pourquoi ne puis-je pas utiliser les expressions lambda lors du débogage dans la fenêtre «Quick watch»?

UPD: voir aussi

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

Les expressions lambda, comme les méthodes anonymes, sont en réalité des bêtes très complexes. Même si nous excluons Expression (.NET 3.5), cela laisse toujours beaucoup de complexité, en particulier en ce qui concerne les variables capturées, qui restructurent fondamentalement le code qui les utilise (ce que vous considérez comme des variables deviennent des champs sur les classes générées par le compilateur) ), avec un peu de fumée et de miroirs.

En tant que tel, je ne suis pas du tout surpris que vous ne puissiez pas les utiliser inutilement – il y a beaucoup de travail de compilation (et de génération de types en coulisse) qui supporte cette magie.

Non, vous ne pouvez pas utiliser les expressions lambda dans la fenêtre watch / locals / immediate. Comme Marc l’a souligné, c’est incroyablement complexe. Je voulais plonger un peu plus loin dans le sujet cependant.

Ce que la plupart des gens ne considèrent pas lors de l’exécution d’une fonction anonyme dans le débogueur, c’est que cela ne se produit pas dans un vide. Le simple fait de définir et d’exécuter une fonction anonyme modifie la structure sous-jacente de la base de code. Changer le code, en général, et en particulier depuis la fenêtre immédiate, est une tâche très difficile.

Considérez le code suivant.

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

Ce code particulier crée une fermeture unique pour capturer la valeur v1. La capture de fermeture est requirejse chaque fois qu’une fonction anonyme utilise une variable déclarée en dehors de sa scope. À toutes fins utiles, v1 n’existe plus dans cette fonction. La dernière ligne ressemble plus à la suivante

 var v3 = closure1.v1 + v2; 

Si la fonction Example est exécutée dans le débogueur, elle s’arrêtera à la ligne Break. Maintenant, imaginez si l’utilisateur tapait ce qui suit dans la fenêtre de surveillance

 (Func)(() => v2); 

Afin de l’exécuter correctement, le débogueur (ou plus approprié, l’EE) devrait créer une fermeture pour la variable v2. C’est difficile mais pas impossible à faire.

Ce qui rend vraiment ce travail difficile pour l’EE, c’est que cette dernière ligne. Comment cette ligne devrait-elle maintenant être exécutée? À toutes fins utiles, la fonction anonyme a supprimé la variable v2 et l’a remplacée par closure2.v2. Donc, la dernière ligne de code doit maintenant lire

 var v3 = closure1.v1 + closure2.v2; 

Cependant, pour obtenir effectivement cet effet dans le code, l’EE doit changer la dernière ligne de code qui est en fait une action ENC. Bien que cet exemple spécifique soit possible, une bonne partie des scénarios ne le sont pas.

Ce qui est encore pire, c’est que l’expression lambda ne devrait pas créer une nouvelle fermeture. Il convient en fait d’append des données à la clôture initiale. À ce stade, vous passez directement aux limitations ENC.

Mon petit exemple ne fait malheureusement qu’effleurer la surface des problèmes que nous rencontrons. Je n’arrête pas de dire que j’écrirai un article complet sur ce sujet et j’espère que j’aurai le temps ce week-end.

Vous ne pouvez pas utiliser les expressions lambda dans les fenêtres Immédiat ou Regarder.

Vous pouvez cependant utiliser les expressions System.Linq.Dynamic , qui prennent la forme .Where (“Id = @ 0”, 2) – il ne dispose pas de la gamme complète des méthodes disponibles dans Linq standard, et n’a pas la pleine puissance des expressions lambda, mais quand même, c’est mieux que rien!

L’avenir est venu!

La prise en charge du débogage des expressions lambda a été ajoutée à Visual Studio 2015 ( Aperçu au moment de la rédaction).

Expression Evaluator a dû être réécrit, de nombreuses fonctionnalités sont manquantes: débogage distant ASP.NET, déclaration de variables dans la fenêtre Immédiat, inspection de variables dynamics, etc. Les expressions lambda qui nécessitent des appels à des fonctions natives ne sont pas sockets en charge actuellement.

cela pourrait aider: Fenêtre immédiate étendue pour Visual Studio (utilisez Linq, Lambda Expr dans le débogage)

Au mieux, Pasortingck

Les expressions lambda ne sont pas sockets en charge par l’évaluateur d’expression du débogueur … ce qui n’a rien d’étonnant car, au moment de la compilation, elles sont utilisées pour créer des méthodes (ou des arbres d’expression) plutôt que des expressions. les voir).

De plus, ils pourraient naturellement former une fermeture, une autre couche complète de structure.

Dans VS 2015, vous pouvez le faire maintenant, c’est l’une des nouvelles fonctionnalités ajoutées.

Si vous devez toujours utiliser Visual Studio 2013, vous pouvez réellement écrire une boucle ou une expression lambda dans la fenêtre immédiate à l’aide de la fenêtre de la console du gestionnaire de packages. Dans mon cas, j’ai ajouté une liste en haut de la fonction:

 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.ToSsortingng()); throw; } } 

Où ma fonction GetAll() est:

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

Ici, j’ai continué à recevoir l’erreur suivante, alors j’ai voulu imprimer tous les éléments dans les différents repositorys:

InnerException {“L’instruction DELETE était en conflit avec la contrainte REFERENCE \” FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ “. Le conflit s’est produit dans la firebase database \” CC_Portal_SchoolObjectModel \ “, table \” dbo.Department \ “, colonne” OranizationalRoleId “. l’instruction a été terminée. “} System.Exception {System.Data.SqlClient.SqlException}

Ensuite, je trouve combien d’enregistrements se trouvent dans le référentiel départemental en l’exécutant dans la fenêtre immédiate:

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

Qui est revenu 243.

Ainsi, si vous exécutez les opérations suivantes dans la console du gestionnaire de packages, tous les éléments sont imprimés:

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

L’auteur de l’idée peut être trouvé ici

Pour répondre à votre question, voici l’explication officielle de Visual Studio Program Manager sur la raison pour laquelle vous ne pouvez pas le faire. En bref, parce que “c’est vraiment très difficile” à mettre en œuvre dans VS. Mais la fonctionnalité est actuellement en cours (mise à jour en août 2014).

Autoriser l’évaluation des expressions lambda lors du débogage

Ajoutez votre vote pendant que vous êtes là!