Công cụ gỡ lỗi Visual Studio "xem nhanh" và biểu thức lambda


96

Tại sao tôi không thể sử dụng biểu thức lambda trong khi gỡ lỗi trong cửa sổ “Xem nhanh”?

UPD: xem thêm

http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx

http://blogs.msdn.com/b/jaredpar/archive/2010/06/02/why-is-linq-absent-from-debugger-windows-part-2.aspx


5
Điều này đã được hoàn thành và có sẵn trong bản xem trước VS 2015. visualstudio.uservoice.com/forums/121579-visual-studio/…
Francisco d'Anconia


tôi đã thử ví dụ rất đơn giản được đưa ra trên MSDN cho biểu thức lambda nhưng nó không hoạt động. tôi có phiên bản doanh nghiệp VS 2015
Adeem

2
@ Franciscod'Anconia để bật hỗ trợ lambda trong gỡ lỗi, "Sử dụng Chế độ tương thích được quản lý" phải được chọn tắt ( stackoverflow.com/a/36559817/818321 ) Do đó, bạn sẽ không thể sử dụng các điểm ngắt có điều kiện: blog.msdn .microsoft.com / devops / 2013/10/16 /…stackoverflow.com/a/35983978/818321
Nik

Câu trả lời:


64

Các biểu thức Lambda, giống như các phương thức ẩn danh, thực sự là những con thú rất phức tạp. Ngay cả khi chúng tôi loại trừ Expression(.NET 3.5), điều đó vẫn để lại rất nhiều phức tạp, đặc biệt là các biến được nắm bắt, về cơ bản cấu trúc lại mã sử dụng chúng (những gì bạn nghĩ khi các biến trở thành trường trên các lớp do trình biên dịch tạo ra) , với một chút khói và gương.

Vì vậy, tôi không ngạc nhiên khi bạn không thể sử dụng chúng một cách nhàn rỗi - có rất nhiều công việc biên dịch (và tạo kiểu phía sau hậu trường) hỗ trợ phép thuật này.


91

Không, bạn không thể sử dụng biểu thức lambda trong cửa sổ đồng hồ / local / ngay lập tức. Như Marc đã chỉ ra, điều này vô cùng phức tạp. Tôi muốn đi sâu hơn một chút vào chủ đề này.

Điều mà hầu hết mọi người không cân nhắc khi thực hiện một chức năng ẩn danh trong trình gỡ lỗi là nó không xảy ra trong khoảng trống. Chính hành động xác định và chạy một hàm ẩn danh sẽ thay đổi cấu trúc cơ bản của cơ sở mã. Thay đổi mã, nói chung, và đặc biệt từ cửa sổ ngay lập tức, là một nhiệm vụ rất khó khăn.

Hãy xem xét đoạn mã sau.

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

Mã cụ thể này tạo ra một lần đóng duy nhất để nắm bắt giá trị v1. Bắt buộc phải nắm bắt được bất cứ khi nào một hàm ẩn danh sử dụng một biến được khai báo bên ngoài phạm vi của nó. Đối với tất cả các ý định và mục đích, v1 không còn tồn tại trong hàm này. Dòng cuối cùng thực sự trông giống như sau

var v3 = closure1.v1 + v2;

Nếu hàm Ví dụ được chạy trong trình gỡ lỗi, nó sẽ dừng ở dòng Break. Bây giờ hãy tưởng tượng nếu người dùng nhập nội dung sau vào cửa sổ xem

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

Để thực thi đúng cách này, trình gỡ lỗi (hoặc thích hợp hơn là EE) sẽ cần tạo một bao đóng cho biến v2. Điều này khó nhưng không phải là không làm được.

Điều thực sự làm cho công việc này trở thành một công việc khó khăn đối với EE mặc dù là dòng cuối cùng. Dòng đó bây giờ nên được thực thi như thế nào? Đối với tất cả các ý định và mục đích, hàm ẩn danh đã xóa biến v2 và thay thế bằng biến close2.v2. Vì vậy, dòng mã cuối cùng thực sự bây giờ cần phải đọc

var v3 = closure1.v1 + closure2.v2;

Tuy nhiên, để thực sự có được hiệu ứng này trong mã yêu cầu EE phải thay đổi dòng mã cuối cùng mà thực sự là một hành động ENC. Trong khi ví dụ cụ thể này là có thể, một phần tốt của các tình huống thì không.

Điều tồi tệ hơn nữa là việc thực thi biểu thức lambda không nên tạo một bao đóng mới. Nó thực sự nên được thêm dữ liệu vào lần đóng ban đầu. Tại thời điểm này, bạn chạy thẳng vào các giới hạn ENC.

Ví dụ nhỏ của tôi không may chỉ làm xước bề mặt của các vấn đề mà chúng tôi gặp phải. Tôi tiếp tục nói rằng tôi sẽ viết một bài blog đầy đủ về chủ đề này và hy vọng tôi sẽ có thời gian vào cuối tuần này.


41
Rên rỉ, than vãn, chấp nhận sự tầm thường, than vãn, than vãn. Trình gỡ lỗi là trung tâm của IDE, và bạn đã phá vỡ nó! Lambdas trong cửa sổ theo dõi không cần chụp bất cứ thứ gì. Giống như bất kỳ mã đồng hồ nào khác, chúng chỉ có ý nghĩa ở khung ngăn xếp cụ thể. (Hoặc nếu bạn nắm bắt biến, di chuyển đến một hàm khác có cùng tên biến ... và những gì?) Trình gỡ lỗi có nghĩa là để hack xung quanh trình biên dịch. Lam cho no hoạt động!
Aleksandr Dubinsky

2
Tại sao chúng đơn giản không cho phép các biến được bắt trên lambdas trên cửa sổ xem. Đơn giản và sẽ cho phép một loạt các kịch bản gỡ lỗi trong đó lambdas chỉ đang được sử dụng trong mã chức năng thực sự.
Luiz Felipe

@LuizFelipe ngay cả khi điều đó vẫn còn rất lớn . Nó yêu cầu EE thực sự tạo ra phần thân chức năng đầy đủ cho lệnh gọi lại (tất cả các cách tới IL). Ngày nay EE không làm gì loại này, thay vào đó nó là một thông dịch viên.
JaredPar

1
@JaredPar bạn có thể chia sẻ blog post marc nói về
Ehsan Sajjad

49

Bạn không thể sử dụng biểu thức lambda trong cửa sổ Ngay lập tức hoặc Xem.

Tuy nhiên, bạn có thể sử dụng biểu thức System.Linq.Dynamic , có dạng .Where ("Id = @ 0", 2) - nó không có đầy đủ các phương thức có sẵn trong Linq tiêu chuẩn và không có đầy đủ sức mạnh của biểu thức lambda, nhưng vẫn tốt hơn là không có gì!


2
Chà ... trong khi những người khác giải thích trong khi điều đó là không thể, điều này ít nhất cung cấp cho chúng tôi một giải pháp khả thi. +1
Nullius

1
Chỉ cần làm rõ, bạn "Import System.Linq.Dynamic" và sau đó trong cửa sổ gỡ lỗi bạn viết "đâu (something.AsQueryable," property> xyz", không có gì)
smirkingman

Điều đó thật tuyệt. Mặc dù bạn không nhận được đầy đủ các phương pháp Linq Extension, chẳng hạn như không có .Any(string predicate), bạn có thể đặt một cái gì đó như: .Where("Id>2").Any()trong Cửa sổ xem hoặc Ghim vào Nguồn. Thật tuyệt vời!
Người bảo vệ một

22

Tương lai đã đến!

Hỗ trợ gỡ lỗi các biểu thức lambda đã được thêm vào Visual Studio 2015 ( Xem trước tại thời điểm viết bài).

Công cụ đánh giá biểu thức đã phải được viết lại, do đó, nhiều tính năng bị thiếu: gỡ lỗi từ xa ASP.NET, khai báo biến trong cửa sổ ngay lập tức, kiểm tra biến động, v.v. Ngoài ra, biểu thức lambda yêu cầu lệnh gọi hàm gốc hiện không được hỗ trợ.


Thật tuyệt khi thấy. Mát mẻ...!
Rahul Nikate


5

điều này có thể hữu ích: Cửa sổ ngay lập tức mở rộng cho Visual Studio (sử dụng Linq, Lambda Expr trong gỡ lỗi)

Tất cả tốt nhất, Patrick


5
Lưu ý rằng mặc dù liên kết đầu tiên trông tuyệt vời, nhưng nó ở dạng alpha và không có khả năng xuất hiện từ nó (cập nhật lần cuối vào năm 2008).
John Salvatier

2

Biểu thức Lambda không được hỗ trợ bởi trình đánh giá biểu thức của trình gỡ lỗi ... điều này hầu như không gây ngạc nhiên vì tại thời điểm biên dịch, chúng được sử dụng để tạo các phương thức (hoặc Cây biểu thức) chứ không phải là biểu thức (hãy xem trong Reflector với màn hình được chuyển sang .NET 2 để nhìn thấy chúng).

Thêm vào đó, tất nhiên chúng có thể tạo thành một lớp đóng cửa, một lớp cấu trúc toàn bộ khác.


Chà, họ có thể tạo ra các phương pháp; họ có thể tạo ra Expressioncây - nó phụ thuộc vào ngữ cảnh.
Marc Gravell

1

Trong VS 2015, bạn có thể làm như vậy ngay bây giờ, đây là một trong những tính năng mới mà họ đã thêm vào.


1

Nếu bạn vẫn cần sử dụng Visual Studio 2013, bạn thực sự có thể viết một vòng lặp hoặc biểu thức lambda trong cửa sổ ngay lập tức bằng cách sử dụng cửa sổ bảng điều khiển trình quản lý gói. Trong trường hợp của tôi, tôi đã thêm một danh sách ở đầu hàm:

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()Chức năng của tôi ở đâu :

private DbSet<T> _dbSet;

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

    return list;
}

Ở đây tôi tiếp tục gặp lỗi sau, vì vậy tôi muốn in ra tất cả các mục trong các kho lưu trữ khác nhau:

InnerException {"Câu lệnh DELETE đã xung đột với ràng buộc REFERENCE \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ ". Xung đột xảy ra trong cơ sở dữ liệu \" CC_Portal_SchoolObjectModel \ ", table \" dbo.Department \ ", cột 'OranizationalRoleRole \". câu lệnh đã bị chấm dứt. "} System.Exception {System.Data.SqlClient.SqlException}

Sau đó, tôi tìm ra có bao nhiêu bản ghi trong kho lưu trữ của bộ phận bằng cách thực hiện điều này trong cửa sổ ngay lập tức:

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

Mà đã trả lại 243.

Vì vậy, nếu bạn thực thi những điều sau trong bảng điều khiển trình quản lý gói, nó sẽ in ra tất cả các mục:

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

Tác giả cho ý tưởng có thể được tìm thấy ở đây


1

Để trả lời câu hỏi của bạn, đây là lời giải thích chính thức của Người quản lý chương trình Visual Studio về lý do tại sao bạn không thể thực hiện việc này. Tóm lại, bởi vì "nó thực sự, rất khó" để thực hiện trong VS. Nhưng tính năng này hiện đang được hoàn thiện (cập nhật vào tháng 8 năm 2014).

Cho phép đánh giá các biểu thức lambda trong khi gỡ lỗi

Thêm phiếu bầu của bạn khi bạn ở đó!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.