เหตุใดฉันจึงไม่สามารถใช้นิพจน์แลมบ์ดาในขณะที่แก้ไขข้อบกพร่องในหน้าต่าง "นาฬิกาด่วน" ได้
UPD: ดูเพิ่มเติม
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
เหตุใดฉันจึงไม่สามารถใช้นิพจน์แลมบ์ดาในขณะที่แก้ไขข้อบกพร่องในหน้าต่าง "นาฬิกาด่วน" ได้
UPD: ดูเพิ่มเติม
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
คำตอบ:
นิพจน์แลมบ์ดาเช่นเดียวกับวิธีการที่ไม่ระบุชื่อเป็นสัตว์ร้ายที่ซับซ้อนมาก แม้ว่าเราจะออกกฎExpression
(NET 3.5) ที่ยังคงใบจำนวนมากของความซับซ้อนไม่น้อยเป็นตัวแปรจับซึ่งพื้นฐานใหม่โครงสร้างรหัสที่ใช้พวกเขา (สิ่งที่คุณคิดว่าเป็นตัวแปรกลายเป็นเขตชั้นเรียนคอมไพเลอร์ที่สร้าง) มีควันและกระจกเล็กน้อย
ด้วยเหตุนี้ฉันจึงไม่แปลกใจเลยที่คุณไม่สามารถใช้มันอย่างเฉยเมย - มีงานคอมไพเลอร์จำนวนมาก (และการสร้างประเภทเบื้องหลัง) ที่สนับสนุนเวทมนตร์นี้
ไม่คุณไม่สามารถใช้นิพจน์แลมบ์ดาในหน้าต่างนาฬิกา / ชาวบ้าน / ทันที ดังที่ 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;
ถ้าฟังก์ชันตัวอย่างถูกเรียกใช้ในดีบักเกอร์มันจะหยุดที่เส้นแบ่ง ลองนึกดูว่าผู้ใช้พิมพ์ข้อความต่อไปนี้ลงในหน้าต่างนาฬิกาหรือไม่
(Func<int>)(() => v2);
ในการดำเนินการนี้อย่างถูกต้องดีบักเกอร์ (หรือ EE ที่เหมาะสมกว่า) จะต้องสร้างการปิดสำหรับตัวแปร v2 นี่เป็นเรื่องยาก แต่ไม่ทำไม่ได้
สิ่งที่ทำให้งานนี้เป็นงานที่ยากสำหรับ EE จริงๆคือบรรทัดสุดท้าย ตอนนี้ควรดำเนินการอย่างไร? สำหรับเจตนาและวัตถุประสงค์ทั้งหมดฟังก์ชันนิรนามจะลบตัวแปร v2 และแทนที่ด้วย closed2.v2 ตอนนี้บรรทัดสุดท้ายของโค้ดจำเป็นต้องอ่านจริงๆ
var v3 = closure1.v1 + closure2.v2;
แต่เพื่อให้ได้เอฟเฟกต์นี้ในโค้ดต้องใช้ EE เพื่อเปลี่ยนบรรทัดสุดท้ายของโค้ดซึ่งเป็นแอ็คชัน ENC แม้ว่าตัวอย่างเฉพาะนี้จะเป็นไปได้ แต่ส่วนที่ดีของสถานการณ์ไม่ได้
สิ่งที่แย่ไปกว่านั้นคือการดำเนินการนิพจน์แลมด้าไม่ควรสร้างการปิดใหม่ ที่จริงแล้วควรต่อท้ายข้อมูลการปิดเดิม ณ จุดนี้คุณจะเข้าสู่ข้อ จำกัด ENC โดยตรง
ตัวอย่างเล็ก ๆ ของฉันน่าเสียดายที่ทำให้เกิดรอยขีดข่วนบนพื้นผิวของปัญหาที่เราพบเท่านั้น ฉันพูดอยู่เสมอว่าจะเขียนบทความในบล็อกเกี่ยวกับเรื่องนี้และหวังว่าฉันจะมีเวลาในสุดสัปดาห์นี้
คุณไม่สามารถใช้นิพจน์แลมบ์ดาในหน้าต่างทันทีหรือดู
อย่างไรก็ตามคุณสามารถใช้นิพจน์ System.Linq.Dynamicซึ่งอยู่ในรูปแบบที่ใด ("Id = @ 0", 2) - มันไม่มีวิธีการทั้งหมดที่มีอยู่ใน Linq มาตรฐานและไม่มีแบบเต็ม พลังแห่งการแสดงออกของแลมบ์ดา แต่ถึงกระนั้นก็ดีกว่าไม่มีอะไรเลย!
.Any(string predicate)
คุณสามารถใส่สิ่งต่างๆเช่น: .Where("Id>2").Any()
ในหน้าต่างนาฬิกาหรือปักหมุดที่แหล่งที่มา มันยอดมาก!
อนาคตมาแล้ว!
เพิ่มการสนับสนุนสำหรับการดีบักนิพจน์แลมบ์ดาในVisual Studio 2015 ( ดูตัวอย่างในขณะที่เขียน)
ต้องมีการเขียน Expression Evaluator คุณสมบัติหลายอย่างจึงขาดหายไป: การดีบัก ASP.NET ระยะไกลการประกาศตัวแปรในหน้าต่างทันทีการตรวจสอบตัวแปรไดนามิกเป็นต้นนอกจากนี้ยังไม่รองรับนิพจน์แลมบ์ดาที่ต้องเรียกใช้ฟังก์ชันเนทีฟ
สิ่งนี้อาจช่วยได้: Extended Immediate Window for Visual Studio (ใช้ Linq, Lambda Expr ในการดีบัก)
ที่ดีที่สุดแพทริค
เครื่องมือประเมินนิพจน์ของดีบักเกอร์ไม่รองรับนิพจน์ ... ซึ่งแทบจะไม่น่าแปลกใจเลยเนื่องจากในเวลาคอมไพล์พวกเขาถูกใช้เพื่อสร้างเมธอด (หรือ Expression Trees) แทนที่จะเป็นนิพจน์ (ดูใน Reflector พร้อมกับการแสดงผลที่เปลี่ยนเป็น. NET 2 เป็น ดูพวกเขา)
นอกจากนี้ยังสามารถก่อตัวปิดซึ่งเป็นโครงสร้างอีกชั้นหนึ่ง
Expression
ต้นไม้ขึ้นอยู่กับบริบท
ใน VS 2015 คุณสามารถทำได้แล้วนี่เป็นหนึ่งในคุณสมบัติใหม่ที่พวกเขาเพิ่มเข้ามา
หากคุณยังต้องใช้ Visual Studio 2013 คุณสามารถเขียน loop หรือ lambda expression ในหน้าต่างทันทีโดยใช้หน้าต่างคอนโซลตัวจัดการแพ็คเกจ ในกรณีของฉันฉันได้เพิ่มรายการที่ด้านบนสุดของฟังก์ชัน:
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 ขัดแย้งกับข้อ จำกัด การอ้างอิง \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ "ความขัดแย้งเกิดขึ้นในฐานข้อมูล \" CC_Portal_SchoolObjectModel \ ", ตาราง \" dbo.Department \ ", คอลัมน์ 'OranizationalRoleId' คำสั่งถูกยกเลิก "} 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 }
ผู้เขียนสำหรับแนวคิดนี้สามารถพบได้ที่นี่
หากต้องการตอบคำถามของคุณนี่คือคำอธิบายอย่างเป็นทางการของ Visual Studio Program Manager เกี่ยวกับสาเหตุที่คุณไม่สามารถทำได้ ในระยะสั้นเพราะ "มันยากจริงๆ" ในการนำไปใช้ใน VS. แต่ฟีเจอร์ดังกล่าวกำลังอยู่ในระหว่างดำเนินการ (อัปเดตเมื่อ ส.ค. 2014)
อนุญาตให้ประเมินนิพจน์แลมบ์ดาขณะดีบัก
เพิ่มคะแนนของคุณในขณะที่คุณอยู่ที่นั่น!