Herramienta de “reloj rápido” de depuración de Visual Studio y expresiones lambda

¿Por qué no puedo usar expresiones lambda mientras se depura en la ventana “Observación rápida”?

UPD: ver también

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

Las expresiones Lambda, al igual que los métodos anónimos, son en realidad bestias muy complejas. Incluso si descartamos Expression (.NET 3.5), eso deja mucha complejidad, sobre todo al ser variables capturadas, que fundamentalmente re-estructuran el código que las usa (lo que usted piensa como variables se convierten en campos en las clases generadas por el comstackdor) ), con un poco de humo y espejos.

Como tal, no estoy en lo más mínimo sorprendido de que no puedas usarlos ociosamente; hay mucho trabajo de comstackción (y generación de tipos entre bastidores) que respalda esta magia.

No, no puede usar expresiones lambda en la ventana watch / locals / immediate. Como Marc ha señalado, esto es increíblemente complejo. Sin embargo, quería adentrarme un poco más en el tema.

Lo que la mayoría de la gente no considera al ejecutar una función anónima en el depurador es que no ocurre en un vacío. El solo hecho de definir y ejecutar una función anónima cambia la estructura subyacente de la base de código. Cambiar el código, en general, y en particular desde la ventana inmediata, es una tarea muy difícil.

Considera el siguiente código.

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

Este código en particular crea un solo cierre para capturar el valor v1. Se requiere captura de cierre siempre que una función anónima use una variable declarada fuera de su scope. Para todos los efectos, v1 ya no existe en esta función. La última línea en realidad se parece más a la siguiente

 var v3 = closure1.v1 + v2; 

Si la función Ejemplo se ejecuta en el depurador, se detendrá en la línea de corte. Ahora imagine si el usuario escribió lo siguiente en la ventana del reloj

 (Func)(() => v2); 

Para ejecutar esto correctamente, el depurador (o más apropiado, el EE) necesitaría crear un cierre para la variable v2. Esto es difícil pero no imposible de hacer.

Sin embargo, lo que realmente hace que este sea un trabajo difícil para EE es esa última línea. ¿Cómo debería ser ejecutada esa línea ahora? Para todos los efectos, la función anónima borró la variable v2 y la reemplazó con closure2.v2. Entonces la última línea de código realmente necesita leer

 var v3 = closure1.v1 + closure2.v2; 

Sin embargo, para obtener este efecto en el código, el EE debe cambiar la última línea de código, que en realidad es una acción ENC. Si bien este ejemplo específico es posible, una buena parte de los escenarios no lo son.

Lo que es aún peor es ejecutar esa expresión lambda no debería estar creando un nuevo cierre. En realidad, debería estar agregando datos al cierre original. En este punto, se ejecuta directamente en las limitaciones ENC.

Mi pequeño ejemplo desafortunadamente solo araña la superficie de los problemas que encontramos. Sigo diciendo que escribiré una publicación completa en este tema y espero tener tiempo este fin de semana.

No puede usar expresiones lambda en las ventanas Inmediato o Watch.

Sin embargo, puede usar expresiones System.Linq.Dynamic , que toman la forma .Where (“Id = @ 0”, 2) – no tiene la gama completa de métodos disponibles en Linq estándar, y no tiene el completo poder de expresiones lambda, pero aún así, ¡es mejor que nada!

¡El futuro ha llegado!

Soporte para la depuración de expresiones lambda se ha agregado a Visual Studio 2015 ( Vista previa en el momento de la escritura).

Expression Evaluator tuvo que ser reescrito, por lo que faltan muchas características: depuración remota de ASP.NET, statement de variables en la ventana Inmediato, inspección de variables dinámicas, etc. Además, las expresiones lambda que requieren llamadas a funciones nativas no son actualmente compatibles.

esto podría ayudar: Ventana Inmediata Extendida para Visual Studio (use Linq, Lambda Expr en Depuración)

Todo lo mejor, Patrick

Las expresiones Lambda no son compatibles con el evaluador de expresiones del depurador … lo cual no es sorprendente ya que en tiempo de comstackción se usan para crear métodos (o Árboles de Expresión) en lugar de expresiones (eche un vistazo en Reflector con la pantalla cambiada a .NET 2 a verlas).

Además, por supuesto, podrían formar un cierre, otra capa completa de estructura.

En VS 2015 puede hacerlo ahora, esta es una de las nuevas características que agregaron.

Si aún necesita usar Visual Studio 2013, puede escribir un bucle o una expresión lambda en la ventana inmediata utilizando también la ventana de la consola del administrador de paquetes. En mi caso, agregué una lista en la parte superior de la función:

 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; } } 

Donde mi función GetAll() es:

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

Aquí seguí recibiendo el siguiente error, así que quería imprimir todos los elementos en los diferentes repositorys:

InnerException {“La instrucción DELETE entró en conflicto con la restricción de REFERENCIA \” FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ “. El conflicto ocurrió en la base de datos \” CC_Portal_SchoolObjectModel \ “, table \” dbo.Department \ “, column ‘OranizationalRoleId’. \ R \ nThe statement ha terminado. “} System.Exception {System.Data.SqlClient.SqlException}

Luego, descubro cuántos registros hay en el repository del departamento al ejecutar esto en la ventana inmediata:

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

Que devolvió 243.

Por lo tanto, si ejecuta lo siguiente en la consola del administrador de paquetes, imprime todos los elementos:

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

El autor de la idea se puede encontrar aquí

Para responder a su pregunta, esta es la explicación oficial del Administrador de progtwigs de Visual Studio de por qué no puede hacer esto. En resumen, porque “es muy, muy difícil” de implementar en VS. Pero la característica está actualmente en progreso (como se actualizó en agosto de 2014).

Permitir la evaluación de expresiones lambda durante la depuración

¡Agregue su voto mientras está allí!