Pourquoi ne puis-je pas utiliser d'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
Les expressions lambda, comme les méthodes anonymes, sont en fait des bêtes très complexes. Même si nous excluons Expression
(.NET 3.5), cela laisse encore un lot de complexité, notamment des variables capturées, qui restructurent fondamentalement le code qui les utilise (ce qui vous pensez que les 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 type dans les coulisses) qui prend en charge cette magie.
Non, vous ne pouvez pas utiliser d'expressions lambda dans la fenêtre watch/locals/immediate. Comme Marc l'a souligné, c'est incroyablement complexe. Je voulais cependant approfondir un peu le sujet.
Ce que la plupart des gens ne considèrent pas avec l'exécution d'une fonction anonyme dans le débogueur, c'est qu'elle ne se produit pas dans un vide. L'acte même 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<int> 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 requise chaque fois qu'une fonction anonyme utilise une variable déclarée en dehors de sa portée. À toutes fins utiles, la 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 de rupture. Imaginez maintenant si l'utilisateur a tapé ce qui suit dans la fenêtre de surveillance
(Func<int>)(() => v2);
Afin d'exécuter correctement cela, 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 en fait vraiment un travail difficile pour l'EE, c'est cette dernière ligne. Comment cette ligne devrait-elle être exécutée maintenant? À toutes fins utiles, la fonction anonyme a supprimé la variable v2 et l'a remplacée par fermeture2.v2. Donc, la dernière ligne de code doit vraiment être lue
var v3 = closure1.v1 + closure2.v2;
Pourtant, pour obtenir réellement cet effet dans le code, l'EE doit modifier 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'exécution de cette expression lambda ne devrait pas créer une nouvelle fermeture. Il devrait en fait ajouter des données à la fermeture d'origine. À ce stade, vous exécutez directement les limitations ENC.
Mon petit exemple ne fait malheureusement qu'effleurer la surface des problèmes que nous rencontrons. Je continue de dire que j'écrirai un article de blog complet sur ce sujet et j'espère avoir du temps ce week-end.
Vous ne pouvez pas utiliser d'expressions lambda dans les fenêtres Exécution ou Surveillance.
Vous pouvez cependant utiliser expressions System.Linq.Dynamic , qui prennent la forme. Où ("Id = @ 0", 2) - il n'a pas 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 ( Preview at the moment de la rédaction).
Expression Evaluator a dû être réécrit, de nombreuses fonctionnalités manquent: débogage à distance ASP.NET, déclaration de variables dans la fenêtre Exécution, inspection des variables dynamiques, etc. Les expressions lambda qui nécessitent des appels à des fonctions natives ne sont pas actuellement prises en charge.
cela pourrait aider: Fenêtre immédiate étendue pour Visual Studio (utilisez Linq, Lambda Expr dans le débogage)
Cordialement, Patrick
Les expressions lambda ne sont pas prises en charge par l'évaluateur d'expression du débogueur ... ce qui n'est pas surprenant puisqu'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 (jetez un œil dans Reflector avec l'affichage basculé sur .NET 2 pour les voir).
De plus, bien sûr, ils pourraient former une fermeture, une autre couche entière de structure.
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 en utilisant également la fenêtre de 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.ToString());
throw;
}
}
Où ma fonction GetAll()
est:
private DbSet<T> _dbSet;
public virtual IList<T> GetAll()
{
List<T> list;
IQueryable<T> dbQuery = _dbSet;
list = dbQuery
.ToList<T>();
return list;
}
Ici, j'ai continué à obtenir l'erreur suivante, donc je voulais imprimer tous les éléments dans les différents référentiels:
InnerException {"L'instruction DELETE est en conflit avec la contrainte REFERENCE \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId\". Le conflit est survenu dans la base de données \" CC_Portal_SchoolObjectModel\", table \" dbo.Department\", colonne\n\The\'d \'. est terminée. "} System.Exception {System.Data.SqlClient.SqlException}
Ensuite, je découvre le nombre d'enregistrements dans le référentiel du département en l'exécutant dans la fenêtre immédiate:
_unitOfWork.DepartmentRepository.GetAll().ToList().Count
Qui a rendu 243.
Donc, si vous exécutez ce qui suit dans la console du gestionnaire de packages, il imprime tous les éléments:
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
Dans VS 2015, vous pouvez le faire maintenant, c'est l'une des nouvelles fonctionnalités qu'ils ont ajoutées.
Pour répondre à votre question, voici l'explication officielle du Gestionnaire de programmes Visual Studio expliquant pourquoi vous ne pouvez pas le faire. En bref, parce que "c'est vraiment, vraiment difficile" à implémenter 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 y êtes!