Dlaczego nie mogę używać wyrażeń lambda podczas debugowania w oknie „Szybki podgląd”?
UPD: patrz także
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Dlaczego nie mogę używać wyrażeń lambda podczas debugowania w oknie „Szybki podgląd”?
UPD: patrz także
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Odpowiedzi:
Wyrażenia lambda, podobnie jak metody anonimowe, są w rzeczywistości bardzo złożonymi bestiami. Nawet jeśli wykluczymy Expression
(.NET 3.5), nadal pozostawia to wiele złożoności, w szczególności bycie zmiennymi przechwytywanymi, które zasadniczo zmieniają strukturę kodu, który ich używa (to, co myślisz o zmiennych, staje się polami w klasach generowanych przez kompilator) , z odrobiną dymu i luster.
W związku z tym nie jestem ani trochę zaskoczony, że nie można ich używać bezczynnie - jest dużo pracy kompilatora (i generowanie typów za kulisami), które wspierają tę magię.
Nie, nie możesz używać wyrażeń lambda w oknie watch / locals / bezpośrednim. Jak zauważył Marc, jest to niezwykle złożone. Chciałem jednak zagłębić się w temat.
Większość ludzi nie bierze pod uwagę wykonywania anonimowej funkcji w debugerze, ponieważ nie występuje ona w próżni. Samo zdefiniowanie i uruchomienie anonimowej funkcji zmienia podstawową strukturę bazy kodu. Zmiana kodu w ogóle, aw szczególności z bezpośredniego okna, jest bardzo trudnym zadaniem.
Rozważmy następujący kod.
void Example() {
var v1 = 42;
var v2 = 56;
Func<int> func1 = () => v1;
System.Diagnostics.Debugger.Break();
var v3 = v1 + v2;
}
Ten konkretny kod tworzy pojedyncze zamknięcie, aby uchwycić wartość v1. Przechwytywanie zamknięcia jest wymagane zawsze, gdy funkcja anonimowa używa zmiennej zadeklarowanej poza jej zakresem. Do wszystkich celów i celów v1 już nie istnieje w tej funkcji. Ostatnia linia w rzeczywistości wygląda bardziej jak następująca
var v3 = closure1.v1 + v2;
Jeśli funkcja Example jest uruchomiona w debugerze, zatrzyma się na linii Break. Teraz wyobraź sobie, że użytkownik wpisał następujące polecenie w oknie zegarka
(Func<int>)(() => v2);
Aby poprawnie to wykonać, debugger (lub bardziej odpowiedni EE) musiałby utworzyć zamknięcie dla zmiennej v2. Jest to trudne, ale nie niemożliwe.
To, co naprawdę sprawia, że jest to ciężka praca dla EE, to ostatnia linijka. Jak powinna teraz zostać wykonana ta linia? Z wszystkich powodów funkcja anonimowa usunęła zmienną v2 i zastąpiła ją closure2.v2. Tak więc ostatnia linia kodu naprawdę musi teraz zostać przeczytana
var v3 = closure1.v1 + closure2.v2;
Jednak aby faktycznie uzyskać ten efekt w kodzie, EE musi zmienić ostatnią linię kodu, która jest w rzeczywistości akcją ENC. Chociaż ten konkretny przykład jest możliwy, spora część scenariuszy nie.
Co gorsza, wykonanie tego wyrażenia lambda nie powinno tworzyć nowego zamknięcia. Powinien faktycznie dołączyć dane do oryginalnego zamknięcia. W tym momencie wbiegasz od razu do ograniczeń ENC.
Mój mały przykład niestety tylko zarysowuje powierzchnię problemów, z którymi się spotykamy. Wciąż powtarzam, że napiszę cały wpis na blogu na ten temat i mam nadzieję, że będę miał czas w ten weekend.
Nie można używać wyrażeń lambda w oknach natychmiastowych ani obserwacyjnych.
Możesz jednak użyć wyrażeń System.Linq.Dynamic , które przyjmują postać .Where ("Id = @ 0", 2) - nie ma pełnego zakresu metod dostępnych w standardowym Linq i nie ma pełnego moc wyrażeń lambda, ale to lepsze niż nic!
.Any(string predicate)
, to można umieścić coś takiego: .Where("Id>2").Any()
w zegarku oknie lub pin do Źródła. Wspaniale!
Przyszła przyszłość!
Obsługa debugowania wyrażeń lambda została dodana do programu Visual Studio 2015 ( wersja zapoznawcza w momencie pisania).
Expression Evaluator musiało zostać przepisane, więc brakuje wielu funkcji: zdalne debugowanie ASP.NET, deklarowanie zmiennych w oknie bezpośrednim, inspekcja zmiennych dynamicznych itp. Również wyrażenia lambda, które wymagają wywołań funkcji natywnych, nie są obecnie obsługiwane.
to może pomóc: Rozszerzone okno bezpośrednie dla programu Visual Studio (użyj Linq, Lambda Expr w debugowaniu)
Wszystkiego najlepszego, Patrick
Wyrażenia lambda nie są obsługiwane przez ewaluator wyrażeń debugera ... co nie jest zaskakujące, ponieważ w czasie kompilacji są używane do tworzenia metod (lub drzew wyrażeń), a nie wyrażeń (spójrz na Reflector z wyświetlaczem przełączonym na .NET 2, aby Zobacz ich).
I oczywiście mogą tworzyć zamknięcie, kolejną całą warstwę struktury.
Expression
drzewa - to zależy od kontekstu.
W VS 2015 możesz to zrobić teraz, jest to jedna z nowych funkcji, które dodali.
Jeśli nadal potrzebujesz korzystać z programu Visual Studio 2013, możesz w rzeczywistości napisać pętlę lub wyrażenie lambda w bezpośrednim oknie, używając również okna konsoli menedżera pakietów. W moim przypadku dodałem listę u góry funkcji:
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;
}
}
Gdzie moja GetAll()
funkcja to:
private DbSet<T> _dbSet;
public virtual IList<T> GetAll()
{
List<T> list;
IQueryable<T> dbQuery = _dbSet;
list = dbQuery
.ToList<T>();
return list;
}
Tutaj ciągle otrzymywałem następujący błąd, więc chciałem wydrukować wszystkie elementy w różnych repozytoriach:
InnerException {"Instrukcja DELETE spowodowała konflikt z ograniczeniem REFERENCE \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ ". Konflikt wystąpił w bazie danych \" CC_Portal_SchoolObjectModel \ ", tabela \" dbo.Department \ ", kolumna„ OranizationalRoleId \ n ”. instrukcja została zakończona. "} System.Exception {System.Data.SqlClient.SqlException}
Następnie sprawdzam, ile rekordów znajduje się w repozytorium działu, wykonując to w bezpośrednim oknie:
_unitOfWork.DepartmentRepository.GetAll().ToList().Count
Który zwrócił 243.
Tak więc, jeśli wykonasz następujące czynności w konsoli menedżera pakietów, wypisze wszystkie elementy:
PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }
Autora pomysłu można znaleźć tutaj
Aby odpowiedzieć na Twoje pytanie, oto oficjalne wyjaśnienie menedżera programu Visual Studio, dlaczego nie możesz tego zrobić. Krótko mówiąc, ponieważ „to naprawdę, bardzo trudne” do zaimplementowania w VS. Ale funkcja jest obecnie w toku (aktualizacja w sierpniu 2014).
Zezwalaj na ocenę wyrażeń lambda podczas debugowania
Dodaj swój głos, gdy tam będziesz!