Czy mogę znaleźć wartość zwracaną przed powrotem podczas debugowania w programie Visual Studio?

387

Weź następującą funkcję:

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

Czy po ustawieniu punktu przerwania w tej funkcji istnieje możliwość sprawdzenia zwróconej wartości? go()jest bezpośrednio sprzężony z datagrid na .aspxstronie.

Jedynym sposobem sprawdzenia zwróconej bazy danych jest użycie zmiennej tymczasowej. Jest to jednak trochę niewygodne. Czy nie ma innej drogi?

doekman
źródło
1
Możesz dodać zegarek, jeśli cofniesz się do stosu wywołań
Chris S
Wydaje mi się, że kiedyś byłeś w stanie to zrobić w VB6. Ale wtedy składnia funkcji wymagała ustawienia wartości funkcji na wartość zwracaną ...
Neil Barnwell
5
Komentarz dla użytkowników Visual C ++: Wpisz $ ReturnValue w oknie natychmiastowym lub oknie podglądu. Przynajmniej na moim VS 2010 zadziałało!
sergiol
9
W przypadku VS2015 użyj $ ReturnValue1 .. ponieważ nie chcesz czytać 20 odpowiedzi i 100 komentarzy poniżej!
felickz 20.04.16
3
Jaka jest odpowiedź na to wszystko w 2019 r.? Te odpowiedzi są przestarzałe.
dylanh724

Odpowiedzi:

264

Nie żebym o tym wiedział. Zauważ, że jeśli zrobić dodać zmienną, zostanie on usunięty przez kompilator w wydaniu buduje tak ...

Aktualizacja: Ta funkcja została dodana do VS2013 . Możesz zobaczyć zwracane wartości w oknach aut lub użyć $ReturnValuew oknie zegarka / natychmiastowym.

Wartość można zobaczyć tylko bezpośrednio po powrocie z funkcji, dlatego najłatwiejszym sposobem uzyskania do niej dostępu jest umieszczenie punktu przerwania w wywołaniu funkcji i przekroczenie (F10) wywołania.


Aktualizacja dla VS2015: boo! niestety nie wygląda na to, że jest w aktualizacji VS2015 (devenv v14)
dla VS2017: wrócił. (devenv v15)

Marc Gravell
źródło
12
Powodem rezygnacji z temp jest czytelność i styl, a nie wydajność, prawda?
OriP
8
Jest to możliwe od wersji VS 2010 z IntelliTrace: blogs.msdn.com/b/habibh/archive/2009/10/23/...
Daniel Hilgarth
2
Intellitrace jest właśnie dostępny w VS Ultimate Edition.
JMGH
3
@MarcGravell Twoja odpowiedź jest zła ! Jasne, zajęło mi to sześć lat między twoją odpowiedzią a MS wypuszczeniem tej funkcji w VS13, ale nadal. Gdybyś tylko dodał „ na razie ”, jako zrzeczenie się ... (Nie, nie jestem opóźniony Jest. To żart, oczywiście jesteś boski, kolego.).
Konrad Viltersten
6
@MarcGravell dla VS2015: $ ReturnValue1 działa! (testowany w wersji ostatecznej)
GY
58

Można to zrobić w Visual Studio 2013 z CLR 4.5.1 zgodnie z witryną z opiniami klientów . Nie był dostępny w poprzednich wersjach dla C #.

(Visual Studio 2008 i wcześniejsze wersje wspierały go dla VB.NET. Zawsze był dostępny dla programistów C / C ++.)

Alex Angas
źródło
1
Jak to zrobić w Visual Studio 2010 C ++?
Użytkownik
Microsoft Connect twierdzi, że istnieje podstawowy problem z kodem zarządzanym, który uniemożliwia jego niezawodne wdrożenie:
Dan Solovay
@ DanSolovay Słowa, których używają, brzmią: „nie mogliśmy konsekwentnie postępować właściwie” (dla VS11), ale „chcą to przywrócić” i „szukają wielu potencjalnych rozwiązań tego problemu”.
Alex Angas,
Wpis połączenia jest nieaktualny. Wydaje się, że funkcja została ... porzucona: (((
Softlion 24.09
1
Jest to możliwe od wersji VS 2010 z IntelliTrace: blogs.msdn.com/b/habibh/archive/2009/10/23/...
Daniel Hilgarth
25

Zgadzam się, że jest to bardzo przydatna rzecz: mieć nie tylko wartość zwracaną przez metodę przed wyjściem z niej, ale także wartość zwracaną przez metody, które właśnie przekroczyłem. Zaimplementowałem go jako część komercyjnego rozszerzenia Visual Studio o nazwie „ OzCode ”.

Dzięki niemu możesz wyświetlić zwracane wartości metod bezpośrednio w edytorze kodu, jako rodzaj wyświetlacza HUD:

Wizualizacja wyciągu

Aby uzyskać więcej informacji, zobacz ten film .

Omer Raviv
źródło
23

Według Microsoft nie ma możliwości niezawodnego wdrożenia tego kodu zarządzanego. Jest to problem, o którym wiedzą i nad którym pracują:

Dla tych, którzy mają doświadczenie w debugowaniu natywnego kodu C ++ lub VB6, być może użyłeś funkcji, w której zwracane są wartości funkcji w oknie Autos. Niestety ta funkcja nie istnieje dla kodu zarządzanego. Chociaż można obejść ten problem, przypisując zwracane wartości do zmiennej lokalnej, nie jest to tak wygodne, ponieważ wymaga modyfikacji kodu. W kodzie zarządzanym o wiele trudniej jest ustalić wartość zwracaną przez funkcję, którą przekroczyłeś. Zdaliśmy sobie sprawę, że nie możemy tutaj robić konsekwentnie, dlatego usunęliśmy tę funkcję, zamiast podawać niepoprawne wyniki w debuggerze. Chcemy jednak Ci to przywrócić, a nasze zespoły CLR i Debugger szukają wielu potencjalnych rozwiązań tego problemu. Niestety nie będzie to częścią 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
źródło
1
Dla @Alex powyżej ( stackoverflow.com/a/3714884/402949 ) jest to dostępne dla VS2013 z CLR 4.5
Dan Solovay
21

Odnośnie Visual Studio 2015:

Zgodnie z obecnie akceptowaną odpowiedzią Marc Gravell:

Ta funkcjonalność została dodana do Visual Studio 2013 . Możesz zobaczyć zwracane wartości w oknach automatycznych lub użyć $ ReturnValue w oknie podglądu / natychmiastowym

W odpowiedzi stwierdzono również, że ta funkcja nie działa w programie Visual Studio 2015. Nie jest to (całkowicie) prawda. Podczas Sprawdź zwracane wartości wywołań metod znajduje się następująca uwaga:

Aby rozpoznano $ ReturnValue, musisz mieć włączone ewaluatory wyrażeń starszego typu (Narzędzia / Opcje / Debugowanie / Użyj starszych ewaluatorów wyrażeń C # i VB ). W przeciwnym razie możesz użyć $ ReturnValue1 .

Przetestowałem to w Visual Studio 2015 Enterprise:

  • Przy wyłączonych ewaluatorach wyrażeń starszych: działa tylko $ ReturnValue1
  • Ze starszymi oceniający wyrażenie włączone: zarówno $ ReturnValue i $ ReturnValue1 pracy
PascalK
źródło
3
Nie wydaje się to już konieczne. W wersji 3 aktualizacji 2015 2015 mam wyłączonych ewaluatorów i $ReturnValuedziała. Jednak wartość zwracana nie pojawia się nigdzie, jeśli masz Use managed compatibility modewłączoną opcję debugowania.
Nick
13

Jeśli przejdziesz do menu NarzędziaOpcje , IntelliTrace i zmienisz ustawienie zbierania zdarzeń i informacji o połączeniach.

Możesz wrócić do poprzedniego zdarzenia wywołania ( Ctrl+ Shift+ F11) i zobaczyć wartość tymczasową zwróconą z wywołania metody w oknie autos jako element potomny nazwy metody.

To nie pokazuje wartości zwracanej dla metody, w której się znajdujesz. Pokazuje tylko wartość zwracaną przez ostatnią metodę wywoływaną w bieżącej metodzie.

Więc jest w porządku

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

ponieważ pokazuje wartość zwracaną dla someTableAdapter.getSomeData().

Ale nie dla:

int go(){return 100 * 99;}
Ross Buggins
źródło
12

Stara sztuczka sprzed dni .NET: Otwórz okno rejestrów i sprawdź wartość rejestru EAX. Zawiera wartość zwracaną przez ostatnią wywoływaną funkcję.

ColinM
źródło
1
+1 dla starej szkoły bliżej podejścia metalowego - to jednak nie zadziała dla wszystkich zwracanych wartości (i to oczywiście zależy od JIT'era - kto wie, jaką szaloną optymalizację może zdecydować, że nie użyje EAX? ). W przypadku typów integralnych będzie (przeważnie?) Działać. Duże typy wartości to inna sprawa (i o ile pamiętam z niektórych postów na blogu, nie będą one również wyświetlane w VS2013).
JimmiTh,
10

Wyjdź z metody go () za pomocą Shift-F11, a następnie w oknie debugowania „Autos” wyświetli wartość zwrotną wywołania metody, która właśnie wyskoczyła ze stosu (w tym przypadku metoda go (), która jest czego chcesz). To jest zachowanie w Visual Studio 2005; Nie korzystałem z programu Visual Studio 2008, więc nie wiem, czy zachowuje się tak samo w tej wersji.

LeopardSkinPillBoxHat
źródło
Próbowałem tego zarówno w VS2005, jak i VS2008, ale tak naprawdę tego nie widzę. Mam otwarte okno „Autos”, ale gdy w funkcji „go”, okno autos jest puste. Również po wyjściu z funkcji (zamykający nawias klamrowy funkcji jest żółty). Czy możesz dać mi jeszcze jedną wskazówkę?
doekman,
Spodziewałbym się, że okno Autos-okno będzie puste podczas WEWNĄTRZ funkcji go (). Musisz WYŁĄCZYĆ całkowicie funkcję (tzn. Kursor debugowania powinien wskazywać na funkcję, która ma WYWOŁANE go ()), a następnie powinieneś zobaczyć wartość zwracaną dla go () w oknie Autos.
LeopardSkinPillBoxHat
@LeopardSkinPillBoxHat: nie mogę tego uruchomić, nawet z dodatkową wskazówką. Próbujesz tego w Visual Basic? Wydaje się, że ma lepsze wsparcie w zakresie obserwacji i zmiany wartości zwracanych ...
Roman Starkov,
@romkyns - Co pojawia się w oknie „Autos”? Czy nie wyświetla linii wskazującej, co ostatnio wywołana funkcja zwróciła?
LeopardSkinPillBoxHat
2
@LeopardSkinPillBoxHat: nie, nie robi tego w C #. PS Wow, zajęło mi to trochę czasu, aby zobaczyć to ponownie.
Roman Starkov
7

Tak, jest bardzo fajny sposób. Istotną wadą jest to, że trzeba będzie czekać 5, może 6 lat. Ponieważ widzę, że napisałeś w listopadzie 2008 r., Sugeruję, abyś ...

... aaaait. I voila! Właśnie dla Ciebie MS wydał najnowszą wersję Visual Studio 2013, w której jest to domyślna funkcja dostępna z menu podczas pracy w trybie debugowania (menu DebugowanieWindowsAutomaty ).

Konrad Viltersten
źródło
@Doug Ponieważ pytanie zostało zadane w listopadzie 2008 r., A moja odpowiedź nadeszła we wrześniu 2014 r. Oryginalny plakat jest prawdopodobnie zadowolony i nie chce przesunąć kredytu. Ale zgadzam się z tobą - nie miałbym nic przeciwko kolejnej zalotności mojej odpowiedzi. Lubię upsies i zdobywanie przedstawicieli. :)
Konrad Viltersten
Miałem dzisiaj ten problem. Dziękujemy za odpowiedź w 2014 r., Mimo że początkowy numer pochodzi z 2008 r. Twoja odpowiedź była tym, czego szukałem.
AP
@AP Brak problemów. Czuję się trochę jak wehikuł czasu, aby zobaczyć ten post. Wybuch z przeszłości, hehe.
Konrad Viltersten
5

Istnieje wiele obejść, ale żadne nie wydaje się zadowalające.

Cytując poniżej Johna Skeeta (skomentuj teraz usuniętą odpowiedź):

Nadal wydaje mi się niewygodny - zwłaszcza jeśli nie wiesz, jakiej wartości zwrotu będziesz potrzebować przed rozpoczęciem debugowania. Naprawdę nie chcę mieć zmiennej tymczasowej zaśmiecającej mój kod za każdym razem, gdy cokolwiek zwracam. T

Teoretycznie debugger może mieć returnzmienną. W końcu: to tylko zmienna na stosie:

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

Rozważ to żądanie funkcji dla programu Visual Studio.

doekman
źródło
istnieje spora różnica między zmienną (dobrze zdefiniowany lokalny) a wartością na stosie. Jest to wartość na stosie, ale nie jest to zmienna (= lokalna).
Marc Gravell
@Marc: Nie jestem pewien, jak działa CLR, ale wiele kompilatorów umieszcza argumenty funkcji na stosie poniżej wskaźnika stosu (sp), a lokalne zmienne na stosie powyżej wskaźnika stosu. Właśnie to próbuję pokazać. I OK, gdy zwracana wartość jest typem referencyjnym, po prostu dostajesz pewną wartość wskaźnika.
doekman
1
To niekoniecznie jest na stosie. W rzeczywistości, jeśli przeglądasz Debugowanie -> Rejestry, możesz zobaczyć to w EAX
Mark Sowul
5

Chciałem rozwinąć odpowiedź PascalK na uruchomienie tej wersji w Visual Studio 2015, ponieważ istnieje ukryta funkcja, która nie jest udokumentowana w Zbadaj wartości zwrotne wywołań metod .

Jeśli zagnieżdżono wywołania funkcji, pseudo-zmienne $ResultValueXsą tworzone automatycznie, gdzie X odnosi się do kolejności wywołań funkcji. Więc jeśli masz wywołanie takie jak Multiply(Five(), Six()), tworzone są następujące pseudo-zmienne:

Five()     | $ResultValue1 = 5
Six()      | $ResultValue2 = 6
Multiply() | $ResultValue3 = 30
splttingatms
źródło
2

Microsoft Visual C ++ kiedyś to robił, ale Visual Studio nie AFAIK .. :(

Sprintstar
źródło
2

Jedyny sposób, jaki znam, to umieszczenie punktu przerwania w linii powrotnej, a następnie wywołanie okna szybkiego podglądu i wprowadzenie zwróconego wyrażenia:

someTableAdapter.getSomeData();

Działa to jednak tylko wtedy, gdy wywołanie nie zmienia stanu żadnego obiektu (ponieważ nastąpi drugie wywołanie tej samej metody, kiedy wznowisz wykonywanie).

Sylvain Rodrigue
źródło
5
Działa to również tylko wtedy, gdy twoje wyrażenie nie ma lambda.
Roman Starkov,
1

Możesz także poprosić o ocenę wartości w oknie pośrednim, jeśli nie ustawia flag lub innych zmiennych, a jedynie coś zwraca.

Biri
źródło
Musisz uwzględnić lambda w pytaniu, ponieważ zbyt często używam bezpośredniego okna
Chris S
1

Myślę, że można to ustalić, patrząc na rejestr RAX w oknie rejestrów (debugowanie / Windows / rejestry). Po wyjściu (SHIFT + F11) z funkcji sprawdź rejestr RAX. Nie wiem na pewno, ale pewnego razu na Księżycu mogłeś sprawdzić rejestr (wcześniej .NET dni) i zobaczyć tam zwracaną wartość. Może to być nawet kombinacja RAX i RBX itp.

Joe Rattz
źródło
1

Otwarcie okna debugowania → autos spowoduje zamknięcie. Nie pokaże rzeczywistej wartości zwracanej, ale pokaże to, co zostało ocenione w instrukcji return.

GeekyMonkey
źródło
2
Nie można uzyskać okna automatycznego VS2008, aby pokazać coś takiego. Czy mógłbyś wyjaśnić?
Roman Starkov,
return x + y; Miałem na myśli to, że jeśli ustawisz punkt przerwania w tym wierszu, wówczas okno debugowania-autos wyświetli bieżące wartości dla xiy. Tak jak powiedziałem, tylko zbliżysz się. Po prostu próbuję być pomocny. Nie sądzę, że to zasługuje na opinię.
GeekyMonkey
1

Tak, przechodząc na VB.NET. ; P (Właśnie powiedziałeś „Visual Studio”.;)

Tak długo, jak pamiętam (od Visual Basic po wszystkie wersje VB.NET), możesz po prostu zapytać o nazwę funkcji. „Funkcjonuje” jak zmienna lokalna, która jest domyślnie zadeklarowana na początku funkcji, a jej bieżąca wartość jest również używana jako wartość zwracana za każdym razem, gdy funkcja kończy działanie za pomocą instrukcji instrukcji non-return (tj.Exit Function Lub po prostu spada) i oczywiście, gdy używana jest instrukcja return.

Jest również ustawiony na wyrażenie instrukcji return. Podobnie jak zmienna lokalna, jej wartość można sprawdzić w dowolnym punkcie wykonania funkcji (w tym po wykonaniu instrukcji return). C # nie ma tego i powinien.

Ta mała funkcja VB.NET (plus Exit Functioninstrukcja, którą włącza - kolejna funkcja C # nie ma i nie powinna) jest bardzo przydatna w formie programowania obronnego , w którym ćwiczę, gdzie zawsze inicjuję nazwę funkcji na wartość błędu / wartości domyślnej jako pierwsze oświadczenie. Następnie w dowolnym punkcie awarii (który zwykle występuje znacznie częściej niż punkty sukcesu), mogę po prostu wywołać Exit Functioninstrukcję (tj. Bez konieczności duplikowania wyrażenia niepowodzenia / domyślnego lub nawet nazwy stałej / zmiennej).

Tomek
źródło
1

Akceptowana odpowiedź nie działa poprawnie z Visual Studio 2015, ale umieszczając punkt przerwania w ostatnim wierszu metody i naciskając F10, umieści wszystkie wyrażenia wartości zwracanej w oknie lokalnych.

Esben Skov Pedersen
źródło
Prawdopodobnie możesz również edytować zaakceptowaną odpowiedź, aby dołączyć swoje komentarze.
doekman
0

Możesz spróbować wybrać "someTableAdapter.getSomeData();", kliknąć prawym przyciskiem myszy i przejść do szybkiego oglądania .

Yann Semet
źródło
-1

Przeciągnij i upuść wyrażenie zwrotne w oknie zegarka.

Na przykład w zestawieniu

return someTableAdapter.getSomeData();

przeciągnij i upuść

someTableAdapter.getSomeData()

w okienku zegarka, a zobaczysz wartość.

Możesz to zrobić dla dowolnego wyrażenia.

Pita.O
źródło
2
Problem z tym: wyrażenie jest oceniane dwukrotnie.
doekman
6
I wyrażenia obserwacyjne nie mogą zawierać wyrażeń lambda, których używam dość często.
Steve Crane