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
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
Câu trả lời:
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.
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.
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ì!
.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!
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ợ.
đ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
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.
Expression
cây - nó phụ thuộc vào ngữ cảnh.
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.
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
Để 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 ở đó!