¿Por qué no puedo usar expresiones lambda mientras depuro en la ventana "Vista rápida"?
UPD: ver también
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
¿Por qué no puedo usar expresiones lambda mientras depuro en la ventana "Vista rápida"?
UPD: ver también
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Respuestas:
Las expresiones lambda, como los métodos anónimos, son en realidad bestias muy complejas. Incluso si descartamos Expression
(.NET 3.5), eso todavía deja mucha complejidad, sobre todo las variables capturadas, que fundamentalmente reestructuran el código que las usa (lo que usted piensa que las variables se convierten en campos en clases generadas por el compilador) , con un poco de humo y espejos.
Como tal, no me sorprende en lo más mínimo que no pueda usarlos sin hacer nada: hay mucho trabajo de compilación (y generación de tipos detrás de escena) que respalda esta magia.
No, no puede usar expresiones lambda en la ventana de observación / locales / inmediata. Como ha señalado Marc, esto es increíblemente complejo. Sin embargo, quería profundizar 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 del código base. Cambiar el código, en general, y en particular desde la ventana inmediata, es una tarea muy difícil.
Considere 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 en particular crea un cierre único para capturar el valor v1. La captura de cierre es necesaria siempre que una función anónima utilice 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 Example se ejecuta en el depurador, se detendrá en la línea Break. Ahora imagina si el usuario escribiera lo siguiente en la ventana de visualización
(Func<int>)(() => v2);
Para ejecutar correctamente esto, 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 la última línea. ¿Cómo debería ejecutarse esa línea ahora? Para todos los efectos, la función anónima eliminó la variable v2 y la reemplazó con closures2.v2. Entonces, la última línea de código realmente necesita leerse
var v3 = closure1.v1 + closure2.v2;
Sin embargo, para obtener realmente este efecto en el código, 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 crear un nuevo cierre. En realidad, debería agregar datos al cierre original. En este punto, corre directamente hacia las limitaciones ENC.
Desafortunadamente, mi pequeño ejemplo solo araña la superficie de los problemas con los que nos encontramos. Sigo diciendo que escribiré una publicación de blog completa sobre este tema y espero tener tiempo este fin de semana.
No puede usar expresiones lambda en las ventanas Inmediato o Inspección.
Sin embargo, puede usar las 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 el poder de las expresiones lambda, pero aún así, ¡es mejor que nada!
.Any(string predicate)
, puede poner algo como: .Where("Id>2").Any()
en la ventana de visualización o Pin to Source. ¡Es genial!
¡Ha llegado el futuro!
Se ha agregado compatibilidad para depurar expresiones lambda en Visual Studio 2015 ( vista previa en el momento de escribir este artículo).
Expression Evaluator tuvo que ser reescrito, faltan muchas características: depuración remota de ASP.NET, declarar variables en la ventana Inmediato, inspeccionar variables dinámicas, etc. Además, las expresiones lambda que requieren llamadas a funciones nativas no son compatibles actualmente.
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 el momento de la compilación se utilizan 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 para verlos).
Además, por supuesto, podrían formar un cierre, otra capa completa de estructura.
Expression
árboles, depende del contexto.
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 expresión lambda en la ventana inmediata usando 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 GetAll()
función 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ía recibiendo el siguiente error, así que quería imprimir todos los elementos de los distintos repositorios:
InnerException {"La declaración DELETE entró en conflicto con la restricción REFERENCE \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ ". El conflicto se produjo en la base de datos \" CC_Portal_SchoolObjectModel \ ", tabla \" dbo.Department \ ", columna '\ nDelRolloResumen \". la declaración ha finalizado. "} System.Exception {System.Data.SqlClient.SqlException}
Luego, averiguo cuántos registros hay en el repositorio del departamento ejecutando esto en la ventana inmediata:
_unitOfWork.DepartmentRepository.GetAll().ToList().Count
Que devolvió 243.
Entonces, 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, aquí está 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 función está actualmente en progreso (actualizada en agosto de 2014).
Permitir la evaluación de expresiones lambda durante la depuración
¡Agregue su voto mientras está allí!