¿Puedo encontrar el valor de retorno antes de regresar mientras se depura en Visual Studio?

387

Tome la siguiente función:

DataTable go() {
    return someTableAdapter.getSomeData();
}

Cuando establezco un punto de interrupción en esta función, ¿existe la posibilidad de inspeccionar el valor devuelto? go()está directamente acoplado a una cuadrícula de datos en una .aspxpágina.

La única forma de inspeccionar la tabla de datos devuelta es usar una variable temporal. Sin embargo, eso es un poco incómodo. ¿No hay otra manera?

Doekman
fuente
1
Puede agregar un reloj si vuelve a subir la pila de llamadas
Chris S
Solía ​​ser capaz de hacer esto en VB6, creo recordar. Pero en aquel entonces la sintaxis para las funciones implicaron ajustar el valor de la función para el valor de retorno ...
Neil Barnwell
55
Comentario para usuarios de Visual C ++: escriba $ ReturnValue en la ventana Inmediato o en la Ventana de observación. ¡Al menos en mi VS 2010 funcionó!
sergiol
99
Para VS2015 use $ ReturnValue1 .. en caso de que no quiera leer las 20 respuestas y 100 comentarios a continuación.
felickz
3
¿Cuál es la respuesta de 2019 a todo esto? Estas respuestas son muy anticuadas.
dylanh724

Respuestas:

264

No que yo sepa. Tenga en cuenta que si haces agregar una variable, que conseguirá eliminado por el compilador en las versiones de lanzamiento de todos modos ...

Actualización: esta funcionalidad se ha agregado a VS2013 . Puede ver los valores de retorno en las ventanas de autos o usar $ReturnValueen la ventana de vigilancia / inmediata.

El valor solo se puede ver directamente después de regresar de la función, por lo tanto, la forma más fácil de acceder es poner un punto de interrupción en la llamada a la función y pasar (F10) la llamada.


Actualización para VS2015: ¡boo! desafortunadamente, no parece estar en la actualización VS2015 (devenv v14)
para VS2017: está de vuelta. (devenv v15)

Marc Gravell
fuente
12
La razón para renunciar a la temperatura es la legibilidad y el estilo, no la eficiencia, ¿no?
oriP
8
Es posible desde VS 2010 con IntelliTrace: blogs.msdn.com/b/habibh/archive/2009/10/23/…
Daniel Hilgarth
2
Intellitrace solo está disponible en VS Ultimate Edition.
JMGH
3
@MarcGravell ¡Tu respuesta es incorrecta ! Claro, me tomó seis años entre su respuesta y MS lanzando esa característica en VS13, pero aún así. Si sólo hubiera tenido añadido " por el momento ", como un descargo de responsabilidad ... (No, no estoy retrasada Es. Es una broma, por supuesto que eres un dios, amigo..)
Konrad Viltersten
66
@MarcGravell para VS2015: ¡$ ReturnValue1 funciona! (probado en la versión definitiva)
GY
58

Esto se puede hacer en Visual Studio 2013 con CLR 4.5.1 de acuerdo con el sitio de comentarios del cliente . No estaba disponible en versiones anteriores para C #.

(Visual Studio 2008 y versiones anteriores lo admitían para VB.NET. Siempre estuvo disponible para los desarrolladores de C / C ++).

Alex Angas
fuente
1
¿Cómo se hace esto en Visual Studio 2010 C ++?
Usuario
Microsoft Connect dice que hay un problema fundamental con el código administrado que impide implementar esto de manera confiable:
Dan Solovay
@DanSolovay Las palabras que usan son "no pudimos hacer lo correcto de manera consistente" (para VS11) pero "quieren recuperar esto" y "están buscando una serie de posibles soluciones a este problema".
Alex Angas
La entrada de conexión está obsoleta. La característica parece estar ... abandonada: ((((
Softlion
1
Es posible desde VS 2010 con IntelliTrace: blogs.msdn.com/b/habibh/archive/2009/10/23/…
Daniel Hilgarth
25

Estoy de acuerdo en que es algo muy útil: no solo ver el valor de retorno del método antes de abandonarlo, sino también ver el valor de retorno de los métodos que acabo de pasar. Lo implementé como parte de una extensión comercial de Visual Studio llamada " OzCode ".

Con él, puede ver los valores de retorno del método directamente en el editor de código, como una especie de pantalla HUD:

Visualización de declaraciones

Para obtener más información, vea este video .

Omer Raviv
fuente
23

Según Microsoft, no hay forma de implementar esto de manera confiable con código administrado. Este es un problema del que conocen y están trabajando:

Para aquellos que tienen experiencia en la depuración de código nativo de C ++ o VB6, es posible que haya utilizado una función en la que se proporcionan valores de retorno de función en la ventana Autos. Desafortunadamente, esta funcionalidad no existe para el código administrado. Si bien puede solucionar este problema asignando los valores de retorno a una variable local, esto no es tan conveniente porque requiere modificar su código. En el código administrado, es mucho más complicado determinar cuál es el valor de retorno de una función que ha superado. Nos dimos cuenta de que no podíamos hacer lo correcto de manera consistente aquí, por lo que eliminamos la función en lugar de brindarle resultados incorrectos en el depurador. Sin embargo, queremos traer esto de vuelta para usted y nuestros equipos CLR y Debugger están buscando una serie de posibles soluciones a este problema. Lamentablemente, esto no será parte de Visual Studio 11.

https://connect.microsoft.com/VisualStudio/feedback/details/597933/add-a-return-pseudo-variable-to-the-visual-studio-debugger-for-net-code

Dan Solovay
fuente
1
Según @Alex arriba ( stackoverflow.com/a/3714884/402949 ), esto está disponible para VS2013 con CLR 4.5
Dan Solovay
21

Con respecto a Visual Studio 2015:

Según la respuesta actualmente aceptada por Marc Gravell:

Esta funcionalidad se ha agregado a Visual Studio 2013 . Puede ver los valores de retorno en las ventanas de autos o usar $ ReturnValue en la ventana de vigilancia / inmediata

Esa respuesta también indicó que esta funcionalidad no funciona en Visual Studio 2015. Esto no es (del todo) verdadero. En Examinar los valores de retorno de las llamadas a métodos hay la siguiente nota:

Debe tener activados los evaluadores de expresiones heredadas para que $ ReturnValue sea ​​reconocido (Herramientas / Opciones / Depuración / Usar los evaluadores de expresiones C # y VB heredados ). De lo contrario, puede usar $ ReturnValue1 .

Probé esto en Visual Studio 2015 Enterprise:

  • Con los evaluadores de expresiones heredadas desactivados: solo $ ReturnValue1 funciona
  • Con los evaluadores de expresiones heredadas activados: tanto $ ReturnValue como $ ReturnValue1 funcionan
PascalK
fuente
3
Esto ya no parece ser necesario. En VS 2015 Update 3, tengo los evaluadores heredados desactivados y $ReturnValuefunciona. Sin embargo, el valor de retorno no aparece en ningún lado si tiene Use managed compatibility modehabilitada la opción de depuración.
Nick
13

Si va al menú HerramientasOpciones , IntelliTrace, y cambia la configuración para recopilar eventos e información de llamadas.

Puede volver al evento de llamada anterior ( Ctrl+ Shift+ F11) y ver el valor temporal devuelto por la llamada al método en la ventana de autos como elemento secundario del nombre del método.

Esto no le muestra el valor de retorno para el método en el que se encuentra. Simplemente le muestra el valor de retorno del último método llamado en el método actual.

Entonces, está bien para

DataTable go(){return someTableAdapter.getSomeData();}

como le muestra el valor de retorno para someTableAdapter.getSomeData().

Pero no para:

int go(){return 100 * 99;}
Ross Buggins
fuente
12

Viejo truco de los días anteriores a .NET: abra la ventana Registros y observe el valor del registro EAX. Contiene el valor de retorno de la última función llamada.

ColinM
fuente
1
+1 para la vieja escuela más cercana al enfoque de metal; sin embargo, esto no funcionará para todos los valores de retorno (y depende de JIT'er, obviamente, ¿quién sabe qué loca optimización podría decidir que no usará EAX? ) Para los tipos integrales funcionará (¿principalmente?). Los tipos de valores grandes son una cuestión diferente (y por lo que recuerdo de alguna publicación de blog, tampoco se mostrarán en VS2013).
JimmiTh
10

Salga del método go () usando Shift-F11, y luego en la ventana de depuración "Autos" mostrará el valor de retorno de la llamada al método que acaba de salir de la pila (en este caso, el método go () que es Lo que quieras). Este es el comportamiento en Visual Studio 2005; No he usado Visual Studio 2008, así que no sé si esto se comporta de la misma manera en esa versión.

LeopardSkinPillBoxHat
fuente
He intentado esto en VS2005 y VS2008, pero realmente no lo veo. Tengo la ventana "Autos" abierta, pero cuando estoy en la función "go", la ventana de autos está vacía. También al salir de la función (la llave de cierre de la función es amarilla). ¿Me puede dar una pista más?
doekman el
Esperaría que la ventana Autos esté vacía mientras DENTRO de la función go (). Debe salir COMPLETAMENTE de la función (es decir, el cursor de depuración debe apuntar a la función LLAMADA go ()) y luego debe ver el valor de retorno para go () en la ventana Autos.
LeopardSkinPillBoxHat
@LeopardSkinPillBoxHat: no puedo hacer que esto funcione, incluso con tu pista adicional. ¿Estás intentando esto en Visual Basic? Parece que tiene un mejor soporte para la observación y el cambio de valores de retorno ...
Romano Starkov
@romkyns: ¿qué se muestra en la ventana "Autos"? ¿No muestra una línea que indica lo que devolvió la última función llamada?
LeopardSkinPillBoxHat
2
@LeopardSkinPillBoxHat: no, no hace eso en C #. PD Wow, me llevó un tiempo ver esto de nuevo.
Roman Starkov
7

Sí, hay una muy buena manera. Un inconveniente importante es que tendrías que esperar 5, quizás 6 años. Desde que vi que publicaste en noviembre de 2008, te sugiero que waaaaaa ...

... aaaait. ¡Y voilá! Solo para usted, MS ha lanzado la última versión de Visual Studio 2013, donde es una característica predeterminada accesible desde los menús mientras se ejecuta en modo de depuración (menú DepurarWindowsAutos ).

Konrad Viltersten
fuente
@Doug Debido a que la pregunta se hizo en noviembre de 2008 y mi respuesta llegó en septiembre de 2014. El póster original probablemente esté satisfecho y no quiera mover el crédito. Pero sí estoy de acuerdo con usted: no me importaría un poco más de respuestas sobre mi respuesta. Me gustan los upsies y la ganancia de repeticiones. :)
Konrad Viltersten
Tuve este problema hoy. Gracias por responder en 2014 a pesar de que el número inicial es de 2008. Su respuesta es lo que estaba buscando.
AP
@AP No hay problemas. Se siente un poco como una máquina del tiempo para ver esta publicación. Explosión del pasado, jeje.
Konrad Viltersten
5

Hay muchas soluciones alternativas, pero ninguna parece satisfactoria.

Para citar a John Skeet a continuación (comentar una respuesta ahora eliminada):

Todavía me parece inconveniente, especialmente si no sabe qué valor de retorno necesitará antes de comenzar a depurar. Realmente no quiero tener que tener una variable temporal saturando mi código cada vez que devuelvo algo.

En teoría, el depurador podría tener una returnvariable. Después de todo: es solo una variable en la pila:

unsafe {
  int * sp = stackalloc int[1];
  try {
    return a+b;
  }
  finally {
    Trace.WriteLine("return is " + *(sp+3));
  }
}

Considere esto una solicitud de función para Visual Studio.

Doekman
fuente
Hay una gran diferencia entre una variable (un local bien definido) y un valor en la pila. Es un valor en la pila, pero no es una variable (= local).
Marc Gravell
@Marc: No estoy seguro de cómo funciona el CLR, pero muchos compiladores colocan argumentos de función en la pila debajo del puntero de pila (sp), y las variables locales en la pila, encima del puntero de pila. Eso es justo lo que estoy tratando de mostrar. Y OK, cuando el valor de retorno es un tipo de referencia, solo obtienes algún valor de puntero.
Doekman
1
No está necesariamente en la pila. De hecho, si ve Depuración -> Registros, es probable que lo vea en EAX
Mark Sowul
5

Quería ampliar la respuesta de PascalK para que esto funcione en Visual Studio 2015, porque hay una característica oculta que no está documentada en Examinar valores de retorno de llamadas a métodos .

Si ha anidado llamadas a funciones, las pseudovariables $ResultValueXse crean automáticamente, donde la X se refiere al orden de las llamadas a funciones. Entonces, si tiene una llamada como Multiply(Five(), Six()), se crean las siguientes pseudovariables:

Five()     | $ResultValue1 = 5
Six()      | $ResultValue2 = 6
Multiply() | $ResultValue3 = 30
splttingatms
fuente
2

Microsoft Visual C ++ solía hacer esto, pero Visual Studio no AFAIK .. :(

Sprintstar
fuente
2

La única manera que sé es colocar un punto de interrupción en la línea de retorno y luego llamar a la ventana Quick Watch e ingresar la expresión devuelta:

someTableAdapter.getSomeData();

Pero esto solo funciona si la llamada no cambia el estado de ningún objeto (ya que habrá una segunda llamada al mismo método cuando reanude la ejecución).

Sylvain Rodrigue
fuente
55
Esto también solo funciona si tu expresión no tiene lambdas.
Roman Starkov
1

También puede solicitar evaluar el valor en la ventana intermedia, si no establece indicadores u otras variables, sino que solo devuelve algo.

Biri
fuente
Debe incluir la lambda en la pregunta, ya que a veces uso la ventana inmediata también
Chris S
1

Creo que puede determinar esto mirando el registro RAX en la ventana Registros (Depuración / Windows / Registros). Después de salir (SHIFT + F11) de la función, verifique el registro RAX. No lo sé con certeza, pero una vez en la luna, podría verificar un registro (antes de los días .NET) y ver el valor de retorno allí. Incluso podría ser una combinación de RAX y RBX, etc.

Joe Rattz
fuente
1

Abrir la ventana Debug → Autos te cierra. No mostrará el valor de retorno real, pero mostrará lo que se evaluó en la declaración de retorno.

GeekyMonkey
fuente
2
No se pudo obtener la ventana de autos VS2008 para mostrar algo así. ¿Podrías aclararlo por favor?
Roman Starkov
return x + y; Lo que quise decir es que si establece un punto de interrupción en esta línea, su ventana Debug-Autos mostrará los valores actuales para x e y. Como dije, solo te acerca. Solo trato de ser útil. No creo que merezca un voto negativo.
GeekyMonkey
1

Sí, cambiando a VB.NET. ; P (Acabas de decir "Visual Studio".;)

Desde que tengo memoria (desde Visual Basic hasta todas las versiones de VB.NET), simplemente puede consultar el nombre de la función. "Funciona" como una variable local que se declara implícitamente al comienzo de la función y su valor actual también se usa como valor de retorno cuando la función sale a través de medios de declaración de no retorno (es decir, Exit Functiono simplemente cayendo) y, por supuesto, cuando Se utiliza la declaración de devolución.

También se establece en la expresión de la declaración de devolución. Al igual que una variable local, su valor se puede inspeccionar en cualquier punto de ejecución dentro de la función (incluso después de que se ejecute la instrucción return). C # no tiene esto y debería.

Esa pequeña característica de VB.NET (más la Exit Functiondeclaración que habilita, otra característica que C # no tiene y debería) es muy útil en una forma de programación defensiva que practico donde siempre inicializo el nombre de la función al valor de falla / predeterminado como el primera declaración Luego, en cualquier punto de falla (que normalmente ocurre con mucha más frecuencia que los puntos de éxito), simplemente puedo llamar a la Exit Functiondeclaración (es decir, sin tener que duplicar la expresión de falla / predeterminada o incluso un nombre constante / variable).

Tom
fuente
1

La respuesta aceptada no funciona correctamente con Visual Studio 2015, pero al colocar un punto de interrupción en la última línea del método y presionar F10, colocará todas las expresiones del valor de retorno en la ventana local.

Esben Skov Pedersen
fuente
Probablemente también pueda editar la respuesta aceptada para incluir sus comentarios.
doekman
0

Puede intentar seleccionar "someTableAdapter.getSomeData();", hacer clic derecho sobre él e ir a Quick Watch .

Yann Semet
fuente
-1

Arrastre y suelte la expresión de retorno en una ventana de observación.

Por ejemplo, en la declaración

return someTableAdapter.getSomeData();

arrastrar y soltar

someTableAdapter.getSomeData()

en una ventana de observación y verás el valor.

Puedes hacer esto para cualquier expresión.

Pita.O
fuente
2
El problema con eso: la expresión se evalúa dos veces.
doekman
66
Y las expresiones watch no pueden contener expresiones lambda, que utilizo bastante.
Steve Crane