2009-04-07 6 views
92

¿Por qué no puedo usar expresiones lambda mientras se depura en la ventana "Observación rápida"?Herramienta de "reloj rápido" de depuración de Visual Studio y expresiones lambda

UPD: véase 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

+5

Esto se ha completado y está disponible en la vista previa de VS 2015. http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2049821-debug-lambda-expressions-planned –

+0

http://gigi.nullneuron.net/gigilabs/vs2015-preview-debugger-support- for-lambdas-y-linq/ – pedram

+0

intenté un ejemplo muy simple dado en MSDN para la expresión lambda pero no funciona. Tengo VS 2015 edición empresarial – Adeem

Respuesta

62

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 aún deja un lote de complejidad, siendo las variables capturadas, que fundamentalmente re-estructuran el código que las usa (lo que usted piensa como variables se convierten en campos en el compilador- clases generadas), con un poco de humo y espejos.

Como tal, no estoy para nada sorprendido de que no pueda usarlos ociosamente - hay un lote lote de trabajo de compilación (y tipo generación detrás de escena) que admite esta magia.

2

expresiones lambda no son compatibles con la expresión evaluador del depurador ... lo cual no es sorprendente ya que en tiempo de compilación que se utilizan para crear métodos (o Expression Trees) en lugar de expresiones (echa un vistazo en Reflector con la pantalla cambiada a .NET 2 para verlas).

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

+0

Bueno, ellos * podrían * crear métodos; pueden crear árboles 'Expression', depende del contexto. –

+0

Por supuesto, ampliado. – Richard

90

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 las personas no consideran 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.

Tenga en cuenta el siguiente código.

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

Este código 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 alcance. 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 se ejecuta el ejemplo en el depurador se detendrá en la línea de rotura. Ahora imagínese si el usuario escribió lo siguiente en la ventana de inspección

(Func<int>)(() => v2); 

Con el fin de ejecutar correctamente este el depurador (o más apropiado el EE) necesitaría para crear un cierre para la variable V2. Esto es difícil pero no imposible de hacer.

Lo que realmente hace que este sea un trabajo difícil para EE es la ú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.Así que la última línea de código realmente necesita ahora para leer

var v3 = closure1.v1 + closure2.v2; 

Sin embargo, para conseguir realmente este efecto en el código requiere EE modificar la última línea de código que es en realidad 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.

+8

+1 por el detalle ... Voy a estar atento a esa entrada en el blog ;-p –

+37

gimoteo, acepte mediocridad, gimoteo, gimoteo. El depurador es el corazón del IDE, ¡y lo rompiste! Lambdas en la ventana del reloj no necesita capturar nada. Como cualquier otro código de reloj, tienen sentido solo en el marco de pila particular. (O bien captura la variable, pasa a otra función con el mismo nombre de variable ... ¿y qué?) El depurador está destinado a piratear el compilador. ¡Hazlo funcionar! –

+2

Por qué simplemente no permiten las variables capturadas en lambdas en la ventana de observación. Simple y permitiría un montón de escenarios de depuración donde lambdas solo se usan en código verdaderamente funcional. –

49

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

Sin embargo, puede utilizar System.Linq.Dynamic expressions, que toma la forma .Where ("Id = @ 0", 2) - no tiene toda la gama de métodos disponibles en Linq estándar, y no tiene toda la potencia de expresiones lambda, pero aún así, ¡es mejor que nada!

+2

Bueno ... mientras que los otros explicaron que no era posible, al menos nos proporciona una posible solución.+1 – Nullius

+1

Solo para aclarar, "Importar System.Linq.Dynamic" y luego en la ventana de depuración que escriba '"Where (something.AsQueryable," property> xyz ", nothing)' – smirkingman

+0

Esto es grandioso. Aunque no use obtener el rango completo de los métodos de extensión de Linq, por ejemplo, no hay '.Any (predicado de cadena)', usted puede poner algo como: '.Where (" Id> 2 "). Any()' en la ventana de observación, o Pin a Source. ¡Es genial! –

1

Para responder a su pregunta, esta es la explicación oficial del Administrador de programas 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).

Allow the evaluation of lambda expressions while debugging

Añadir su voto mientras estás allí!

20

¡El futuro ha llegado!

Support for debugging lambda expressions has been added to Visual Studio 2015 (Vista previa en el momento de la escritura).

Expression Evaluator tuvo que reescribirse, por lo que faltan muchas características: depuración remota ASP.NET, declarar variables en la ventana Inmediato, inspeccionar variables dinámicas, etc. Las expresiones lambda que requieren llamadas a funciones nativas no son compatibles.

+0

Eso es agradable de ver. ¡Genial ...! –

+0

[No se puede usar esta característica con el modo de compatibilidad administrada ni con los evaluadores de expresiones C#/VB heredados] (http://stackoverflow.com/questions/36559399/lambda-expressions-in-immediate-window-for-vs2015) – Chris

1

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, he añadido 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<T> _dbSet; 

public virtual IList<T> GetAll() 
{ 
    List<T> list; 
    IQueryable<T> dbQuery = _dbSet; 
    list = dbQuery 
     .ToList<T>(); 

    return list; 
} 

Aquí seguí recibiendo el siguiente error, así que quería imprimir todos los artículos en los diferentes repositorios:

InnerException { "la instrucción DELETE en conflicto con la restricción de referencia \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ "el conflicto se produjo en la base de datos \" CC_P ortal_SchoolObjectModel \ "mesa \ "dbo.Department \", la columna 'OranizationalRoleId'. \ r comunicado \ nLa se ha terminado."} {System.Exception System.Data.SqlClient.SqlException}

Entonces, saber cuántos registros se encuentran en el repositorio departamento mediante la ejecución de este en la ventana inmediata:

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

que volvió 243.

por lo tanto, si se ejecuta el siguiente en la consola del gestor de paquetes, se imprimen todos los artículos:

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 here

1

En VS 2015 puede hacerlo ahora, este es uno de la nueva característica, agregaron.

Cuestiones relacionadas