มีผลข้างเคียงของการส่งคืนจากภายในคำสั่ง using () หรือไม่?


125

การส่งคืนค่าวิธีการจากภายในคำสั่งใช้ที่ได้รับ DataContext ดูเหมือนจะทำงานได้ดีเสมอเช่นนี้:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return transaction;
    }
}

แต่ฉันมักจะรู้สึกว่าฉันควรจะปิดบางอย่างก่อนที่จะแยกออกจากวงเล็บที่ใช้เช่นโดยการกำหนดธุรกรรมก่อนคำสั่งใช้รับมูลค่าภายในวงเล็บแล้วกลับมาหลังวงเล็บ

การกำหนดและส่งคืนตัวแปรนอกวงเล็บใช้จะเป็นการปฏิบัติที่ดีกว่าหรืออนุรักษ์ทรัพยากรด้วยวิธีใด


1
อาจเป็นเรื่องน่าสนใจที่จะดู IL ทั่วไปสำหรับรูปแบบนี้ ฉันสงสัยว่า IL ที่สร้างขึ้นจะมีความแตกต่างกันเล็กน้อย โดยปกติฉันจะไม่กังวลกับการประกาศธุรกรรม var - เพียงแค่ส่งคืนผลลัพธ์ของนิพจน์
Jonesie

คำตอบ:


164

ไม่ฉันคิดว่ามันชัดเจนกว่านี้ ไม่ต้องกังวลDisposeจะยังคงถูกเรียกว่า "กำลังออก" - และหลังจากประเมินมูลค่าที่ส่งคืนครบถ้วนแล้วเท่านั้น หากมีข้อยกเว้นเกิดขึ้น ณ จุดใด ๆ (รวมถึงการประเมินมูลค่าที่ส่งคืน) Disposeจะยังคงถูกเรียกด้วยเช่นกัน

ในขณะที่คุณสามารถใช้เส้นทางที่ยาวกว่าได้อย่างแน่นอนแต่ก็มีสองบรรทัดพิเศษที่เพิ่มจุดแข็งและบริบทพิเศษเพื่อติดตาม (ทางจิตใจ) ในความเป็นจริงคุณไม่จำเป็นต้องใช้ตัวแปรท้องถิ่นเพิ่มเติม - แม้ว่าจะมีประโยชน์ในแง่ของการดีบักก็ตาม คุณสามารถมี:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return (from t in db.Transactions
                orderby t.WhenCreated descending
                where t.Id == singleId
                select t).SingleOrDefault();
    }
}

อันที่จริงฉันอาจถูกล่อลวงให้ใช้สัญกรณ์จุดและวางWhereเงื่อนไขไว้ในSingleOrDefault:

public static Transaction GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        return db.Transactions.OrderByDescending(t => t.WhenCreated)
                              .SingleOrDefault(t => t.Id == singleId);
    }
}

2
Sine คือคุณ @jon จะยังปลอดภัยหรือไม่หากมีข้อยกเว้นถูกโยนเข้าไปในบล็อกโดยใช้
Dave Archer

6
ใช่. การใช้เป็นเพียงแค่น้ำตาลในการสังเคราะห์สำหรับการลอง / สร้างในที่สุด
Mitch Wheat

@David: อย่างที่ Mitch บอกไม่เป็นไร - ฉันได้อัปเดตคำตอบเพื่อให้ชัดเจนขึ้น :)
Jon Skeet

2
เหตุใดจึงต้องใช้ OrderByDescending ร่วมกับ SingleOrDefault
erikkallen

2
@erikkallen: LINQ ไม่มี "MaxBy" น่าเสียดาย - ดังนั้นคุณจึงไม่สามารถรับแถวที่มีค่าสูงสุดได้ สำหรับ LINQ to Objects คุณสามารถเขียนของคุณเองได้ค่อนข้างง่าย แต่ฉันไม่แน่ใจว่าจะทำได้ดีกว่าในกรณีนี้ คุณจะแนะนำอะไรแทน
Jon Skeet

32

ลองดูที่นี่

การทำความเข้าใจคำสั่ง 'ใช้' ใน C #

CLR แปลงรหัสของคุณเป็น MSIL และคำสั่งการใช้งานจะถูกแปลเป็นการทดลองและปิดกั้นในที่สุด นี่คือวิธีแสดงคำสั่งการใช้ใน IL คำสั่งใช้ถูกแปลเป็นสามส่วน: การได้มาการใช้งานและการกำจัด ทรัพยากรจะได้รับก่อนจากนั้นการใช้งานจะอยู่ในคำสั่ง try พร้อมกับประโยคสุดท้าย จากนั้นวัตถุจะถูกกำจัดในประโยคสุดท้าย


4
ข้อมูลเชิงลึกที่น่าสนใจ ขอบคุณ
Kangkan

1
นั่นแปลคำถามเป็น: ผลข้างเคียงใด ๆ ของการกลับมาจากการบล็อกของการลองในที่สุด?
Henk Holterman

3
ไม่สุดท้ายจะถูกเรียกเสมอ techinterviews.com/interview-questions-for-c-developers
Adriaan Stander

6

นอกจากนี้ไม่มีผลข้างเคียงของกลับมาจากภายในusing()คำสั่ง

ไม่ว่าจะทำให้โค้ดอ่านง่ายที่สุดคือการสนทนาอื่น


0

ฉันคิดว่ามันเหมือนกันหมด ไม่มีอะไรเลวร้ายในรหัส NET Framework จะไม่สนใจว่าวัตถุจะถูกสร้างขึ้นที่ใด สิ่งที่สำคัญคือมีการอ้างอิงหรือไม่


-1

ใช่อาจมีผลข้างเคียง ตัวอย่างเช่นหากคุณใช้เทคนิคเดียวกันในวิธีการดำเนินการ ASP.NET MVC คุณจะได้รับข้อผิดพลาดต่อไปนี้: "อินสแตนซ์ ObjectContext ถูกกำจัดและไม่สามารถใช้สำหรับการดำเนินการที่ต้องใช้การเชื่อมต่อได้อีกต่อไป"

public ActionResult GetMostRecentTransaction(int singleId)
{
    using (var db = new DataClasses1DataContext())
    {
        var transaction = (from t in db.Transactions
                              orderby t.WhenCreated descending
                              where t.Id == singleId
                              select t).SingleOrDefault();
        return PartialView("_transactionPartial", transaction);
    }
}

2
หากคุณกำหนดธุรกรรมนอกการใช้ใบแจ้งยอดคุณจะได้รับข้อผิดพลาดเดียวกัน การใช้คีย์เวิร์ดไม่เกี่ยวข้องกับกรณีนี้
Costa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.