Visual Studio 디버깅 "빠른 조사"도구 및 람다 식


96

5
이 작업이 완료되었으며 VS 2015 미리보기에서 사용할 수 있습니다. visualstudio.uservoice.com/forums/121579-visual-studio/…
Francisco d' Anconia


나는 람다 표현을 위해 MSDN에 주어진 매우 간단한 예제를 시도했지만 작동하지 않습니다. 내가 VS 2015 엔터프라이즈 버전을 사용
아데 엠

2
@ Franciscod'Anconia가 디버그에서 람다 지원을 활성화하려면 "관리되는 호환성 모드 사용"을 선택 해제해야합니다 ( stackoverflow.com/a/36559817/818321 ) 결과적으로 조건부 중단 점을 사용할 수 없습니다 : blogs.msdn .microsoft.com / devops / 2013 / 10 / 16 /…stackoverflow.com/a/35983978/818321
Nik

답변:


64

익명 메서드와 마찬가지로 Lambda 식은 실제로 매우 복잡한 짐승입니다. 제외하더라도 Expression(.NET 3.5) 여전히 많은 복잡성을 남깁니다. , 약간의 연기와 거울이 있습니다.

따라서이 마법을 지원 하는 많은 컴파일러 작업 (및 뒤에서 유형 생성)이 있습니다.


91

아니요, 감시 / 지역 / 직접 창에서 람다 식을 사용할 수 없습니다. Marc가 지적했듯이 이것은 매우 복잡합니다. 그래도 주제에 대해 좀 더 자세히 알아보고 싶었습니다.

대부분의 사람들이 디버거에서 익명 함수를 실행할 때 고려하지 않는 것은 진공 상태에서 발생하지 않는다는 것입니다. 익명 함수를 정의하고 실행하는 바로 그 행위는 코드베이스의 기본 구조를 변경합니다. 일반적으로 특히 즉각적인 창에서 코드를 변경하는 것은 매우 어려운 작업입니다.

다음 코드를 고려하십시오.

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

이 특정 코드는 v1 값을 캡처하기 위해 단일 클로저를 생성합니다. 익명 함수가 범위 밖에서 선언 된 변수를 사용할 때마다 클로저 캡처가 필요합니다. 모든 의도와 목적을 위해 v1은 더 이상이 기능에 존재하지 않습니다. 마지막 줄은 실제로 다음과 비슷합니다.

var v3 = closure1.v1 + v2;

Example 함수가 디버거에서 실행되면 Break 라인에서 중지됩니다. 이제 사용자가 감시 창에 다음을 입력했다고 상상해보십시오.

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

이를 제대로 실행하기 위해 디버거 (또는 더 적절한 EE)는 변수 v2에 대한 클로저를 생성해야합니다. 이것은 어렵지만 불가능하지는 않습니다.

이것이 EE에게 정말 힘든 일을 만드는 것은 마지막 라인입니다. 이제 그 라인을 어떻게 실행해야합니까? 모든 의도와 목적을 위해 익명 함수는 v2 변수를 삭제하고이를 closure2.v2로 대체했습니다. 따라서 코드의 마지막 줄은 이제 실제로 읽어야합니다.

var v3 = closure1.v1 + closure2.v2;

그러나 실제로 코드에서이 효과를 얻으려면 EE가 실제로 ENC 작업 인 코드의 마지막 줄을 변경해야합니다. 이 특정 예는 가능하지만 시나리오의 좋은 부분은 그렇지 않습니다.

더 나쁜 것은 람다 표현식이 새로운 클로저를 생성하지 않아야한다는 것입니다. 실제로 원래 클로저에 데이터를 추가해야합니다. 이 시점에서 ENC 한계로 곧장 실행됩니다.

내 작은 예는 불행히도 우리가 직면 한 문제의 표면을 긁는 것뿐입니다. 이 주제에 대한 전체 블로그 게시물을 작성하겠다고 계속 말하고 이번 주말에 시간이 있기를 바랍니다.


41
우는 소리, 우는 소리, 평범함을 받아들이고, 우는 소리, 우는 소리. 디버거는 IDE의 핵심입니다. 감시 창의 Lambda는 아무것도 캡처 할 필요가 없습니다. 다른 시계 코드와 마찬가지로 특정 스택 프레임에서만 의미가 있습니다. (그렇지 않으면 변수를 캡처하고 같은 변수 이름을 가진 다른 함수로 이동합니다 ... 그리고 무엇입니까?) 디버거는 컴파일러를 해킹하기위한 것입니다. 작동하게 만들다!
알렉산드르 Dubinsky

2
워치 윈도우에서 람다에 캡처 된 변수를 허용하지 않는 이유. 간단하며 람다가 진정한 기능 코드에서 사용되는 디버그 시나리오를 허용합니다.
Luiz Felipe

@LuizFelipe 그것조차도 여전히 엄청난 양 입니다. EE가 실제로 콜백을위한 전체 기능 본문을 생성해야합니다 (IL까지). EE는 오늘날 이런 종류의 작업을하지 않고 대신 통역사입니다.
JaredPar 2014 년

1
@JaredPar는 얘기 포스트 마크 블로그를 공유 할 수 있습니다
에산 사자 드

49

직접 실행 또는 조사 식 창에서는 람다 식을 사용할 수 없습니다.

그러나 .Where ( "Id = @ 0", 2) 형식을 취하는 System.Linq.Dynamic 식을 사용할 수 있습니다. 표준 Linq에서 사용할 수있는 전체 메서드 범위가없고 전체가 없습니다. 람다 식의 힘이지만 여전히 아무것도없는 것보다 낫습니다!


2
글쎄요 ... 다른 사람들은 그것이 불가능한 동안 설명했지만, 이것은 적어도 가능한 해결책을 우리에게 제공합니다. 한
Nullius

1
그냥 당신이 "가져 오기 System.Linq.Dynamic"을 명확히하고 디버그 창에 당신은 쓰기 ' "어디 (something.AsQueryable,"속성> XYZ ", 아무것도)'
smirkingman

이것은 훌륭합니다. Linq Extension 메서드의 전체 범위를 얻지 못하더라도 (예 : no) .Any(string predicate), Watch Window 또는 Pin to Source 와 같은 것을 넣을 수 있습니다.Where("Id>2").Any() . 훌륭합니다!
프로텍터 원

22

미래가 왔습니다!

람다 식 디버깅에 대한 지원이 Visual Studio 2015 에 추가되었습니다 ( 작성 당시 미리보기 ).

Expression Evaluator를 다시 작성해야했기 때문에 ASP.NET 원격 디버깅, 직접 실행 창에서 변수 선언, 동적 변수 검사 등 많은 기능이 누락되었습니다. 또한 네이티브 함수를 호출해야하는 람다 식은 현재 지원되지 않습니다.


만나서 반가워요. 멋있는...!
Rahul Nikate 2015 년



2

람다 식은 디버거의 식 평가 기에서 지원되지 않습니다. 컴파일 타임에식이 아닌 메서드 (또는 식 트리)를 생성하는 데 사용되기 때문에 놀라운 일이 아닙니다 (디스플레이가. 그들을 참조하십시오).

물론 그들은 폐쇄, 또 다른 전체 구조 층을 형성 할 수 있습니다.


글쎄, 그들은 방법을 만들 있습니다. 그들은 Expression나무를 만들 수 있습니다 -그것은 상황에 따라 다릅니다.
Marc Gravell

1

VS 2015에서는 지금 그렇게 할 수 있습니다. 이것은 그들이 추가 한 새로운 기능 중 하나입니다.


1

Visual Studio 2013을 계속 사용해야하는 경우 패키지 관리자 콘솔 창을 사용하여 직접 실행 창에 루프 또는 람다 식을 실제로 작성할 수 있습니다. 제 경우에는 함수 상단에 목록을 추가했습니다.

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;
    }
}

GetAll()기능은 다음과 같습니다.

private DbSet<T> _dbSet;

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

    return list;
}

여기에서 다음과 같은 오류가 계속 발생하여 다양한 저장소의 모든 항목을 인쇄하고 싶었습니다.

InnerException { "DELETE 문이 REFERENCE 제약 조건 \"FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ "와 충돌했습니다. 충돌은 데이터베이스 \"CC_Portal_SchoolObjectModel \ ", 테이블 \"dbo.Department \ ", 'OranizationalRoleId'열에서 발생했습니다. \ r \ n 문이 종료되었습니다. "} System.Exception {System.Data.SqlClient.SqlException}

그런 다음 즉시 창에서 실행하여 부서 저장소에 몇 개의 레코드가 있는지 확인합니다.

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

243을 반환했습니다.

따라서 패키지 관리자 콘솔에서 다음을 실행하면 모든 항목이 인쇄됩니다.

PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }

아이디어의 저자는 여기 에서 찾을 수 있습니다.


1

질문에 대답하기 위해 Visual Studio 프로그램 관리자의 공식 설명이 있습니다. 간단히 말해서, VS에서 구현하는 것이 "정말, 정말 어렵습니다". 그러나이 기능은 현재 진행 중입니다 (2014 년 8 월 업데이트 됨).

디버깅하는 동안 람다 식 평가 허용

거기있는 동안 투표를 추가하세요!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.