โครงสร้างเทียบกับคลาส


95

ฉันกำลังจะสร้าง 100,000 วัตถุในรหัส มีขนาดเล็กมีเพียง 2 หรือ 3 คุณสมบัติ ฉันจะใส่ไว้ในรายการทั่วไปและเมื่อพวกเขาเป็นห่วงฉันจะให้พวกเขาและความคุ้มค่าการตรวจสอบและความคุ้มค่าการปรับปรุงอาจจะab

การสร้างวัตถุเหล่านี้เป็นคลาสหรือโครงสร้างเร็วขึ้น / ดีขึ้นหรือไม่

แก้ไข

ก. คุณสมบัติเป็นประเภทค่า (ยกเว้นสตริงที่ฉันคิด?)

ข. พวกเขาอาจ (เรายังไม่แน่ใจ) มีวิธีตรวจสอบ

แก้ไข 2

ฉันสงสัยว่า: อ็อบเจ็กต์บนฮีปและสแต็กประมวลผลโดยตัวเก็บขยะเท่า ๆ กันหรือไม่หรือทำงานแตกต่างกัน?


2
พวกเขาจะมีที่สาธารณะเท่านั้นหรือพวกเขาจะมีวิธีการ? ประเภทเป็นประเภทดั้งเดิมเช่นจำนวนเต็มหรือไม่ พวกเขาจะอยู่ในอาร์เรย์หรือในบางอย่างเช่น List <T>?
JeffFerguson

14
รายการโครงสร้างที่ไม่แน่นอน? ระวัง velociraptor
Anthony Pegram

1
@Anthony: ฉันกลัวว่าฉันจะพลาดเรื่องตลกของ velociraptor: -s
Michel

5
เรื่องตลกของ velociraptor มาจาก XKCD แต่เมื่อคุณโยนไปรอบ ๆ 'ประเภทค่าถูกจัดสรรบนสแต็ค' ความเข้าใจผิด / รายละเอียดการใช้งาน (ลบตามที่เกี่ยวข้อง) นั่นคือ Eric Lippert ที่คุณต้องระวัง ...
Greg Beech

คำตอบ:


138

มันเร็วขึ้นในการสร้างวัตถุเหล่านี้เป็นชั้นหรือเป็น struct?

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

โครงสร้างใช้หน่วยความจำฮีปน้อยลง (เนื่องจากมีขนาดเล็กและบีบอัดได้ง่ายกว่าไม่ใช่เพราะ "อยู่บนสแต็ก") แต่ใช้เวลาคัดลอกนานกว่าสำเนาอ้างอิง ฉันไม่รู้ว่าเมตริกประสิทธิภาพของคุณใช้สำหรับการใช้หน่วยความจำหรือความเร็วเป็นอย่างไร มีการแลกเปลี่ยนที่นี่และคุณเป็นคนที่รู้ว่ามันคืออะไร

การสร้างวัตถุเหล่านี้เป็นคลาสหรือโครงสร้างจะดีกว่าไหม

บางทีชั้นอาจจะมีโครงสร้าง ตามกฎทั่วไป: ถ้าวัตถุมี
ขนาด: 1. เล็ก
2. มีเหตุผลเป็นค่าที่ไม่เปลี่ยนรูป
3. มีจำนวนมาก
นั้นฉันจะพิจารณาทำให้เป็นโครงสร้าง มิฉะนั้นฉันจะยึดติดกับประเภทการอ้างอิง

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

วัตถุบนฮีปและสแต็กประมวลผลโดยตัวเก็บขยะอย่างเท่าเทียมกันหรือไม่

ไม่มีพวกเขาจะไม่เหมือนกันเพราะวัตถุบนสแต็คที่มีรากของคอลเลกชัน คนเก็บขยะไม่จำเป็นต้องถามว่า "มีสิ่งนี้อยู่บนกองขยะไหม" เพราะคำตอบสำหรับคำถามนั้นคือ "ใช่มันอยู่ในสแต็ก" เสมอ (ตอนนี้คุณไม่สามารถพึ่งพาที่จะรักษาวัตถุมีชีวิตอยู่ได้เนื่องจากสแต็กเป็นรายละเอียดการใช้งานตัวกระวนกระวายใจได้รับอนุญาตให้แนะนำการเพิ่มประสิทธิภาพที่กล่าวว่าลงทะเบียนสิ่งที่ปกติจะเป็นค่าสแต็กจากนั้นจะไม่อยู่ในสแต็ก ดังนั้น GC จึงไม่รู้ว่ามันยังมีชีวิตอยู่วัตถุที่ลงทะเบียนสามารถมีการรวบรวมลูกหลานของมันอย่างก้าวร้าวทันทีที่การลงทะเบียนที่ถือครองมันจะไม่ถูกอ่านอีกครั้ง)

แต่คนเก็บขยะจะต้องปฏิบัติต่อวัตถุบนสแต็กเหมือนมีชีวิตเช่นเดียวกับที่ปฏิบัติต่อวัตถุใด ๆ ที่รู้ว่ามีชีวิตเหมือนมีชีวิต อ็อบเจ็กต์บนสแต็กสามารถอ้างถึงอ็อบเจ็กต์ที่จัดสรรฮีปซึ่งจำเป็นต้องมีชีวิตอยู่ดังนั้น GC จึงต้องปฏิบัติกับอ็อบเจ็กต์สแต็กเช่นอ็อบเจ็กต์ที่จัดสรรฮีปที่มีชีวิตเพื่อวัตถุประสงค์ในการกำหนดไลฟ์เซ็ต แต่เห็นได้ชัดว่าพวกมันไม่ได้รับการปฏิบัติในฐานะ "วัตถุที่มีชีวิต" เพื่อจุดประสงค์ในการบีบอัดฮีปเพราะพวกมันไม่ได้อยู่บนฮีปตั้งแต่แรก

ที่ชัดเจน?


เอริคคุณรู้หรือไม่ว่าคอมไพเลอร์หรือตัวกระวนกระวายใจใช้การไม่เปลี่ยนรูป (อาจบังคับด้วยreadonly) เพื่ออนุญาตการเพิ่มประสิทธิภาพ ฉันจะไม่ปล่อยให้สิ่งนั้นมีผลต่อการเลือกความไม่แน่นอน (ฉันเป็นคนสำคัญสำหรับรายละเอียดด้านประสิทธิภาพในทางทฤษฎี แต่ในทางปฏิบัติการก้าวไปสู่ประสิทธิภาพครั้งแรกของฉันพยายามที่จะมีการรับประกันความถูกต้องอย่างง่าย ๆ เท่าที่จะทำได้และไม่จำเป็นต้อง วงจร CPU และวงจรสมองที่เสียไปในการตรวจสอบและ Edge-case และการเปลี่ยนแปลงอย่างเหมาะสมหรือไม่เปลี่ยนรูปจะช่วยได้) แต่มันจะตอบโต้ปฏิกิริยาที่เข่ากระตุกต่อการบอกว่าการไม่เปลี่ยนรูปของคุณอาจช้าลง
จอนฮันนา

@ จอน: คอมไพเลอร์ C # ปรับข้อมูลconstให้เหมาะสมแต่ไม่ใช่ข้อมูลแบบอ่านอย่างเดียว ฉันไม่ทราบว่าคอมไพลเลอร์ jit ทำการเพิ่มประสิทธิภาพการแคชบนฟิลด์แบบอ่านอย่างเดียว
Eric Lippert

น่าเสียดายที่ฉันรู้ว่าความรู้เกี่ยวกับความไม่เปลี่ยนรูปทำให้เกิดการมองโลกในแง่ดีได้ แต่ถึงขีด จำกัด ของความรู้ทางทฤษฎีของฉัน ณ จุดนั้น แต่ก็มีขีด จำกัด ที่ฉันอยากจะยืดออกไป ในระหว่างนี้ "มันเร็วขึ้นได้ทั้งสองวิธีนี่คือเหตุผลตอนนี้ให้ทดสอบและค้นหาว่าวิธีใดใช้ได้ในกรณีนี้" มีประโยชน์ที่จะพูด :)
จอนฮันนา

ฉันอยากจะแนะนำให้อ่านsimple-talk.com/dotnet/.net-framework/…และบทความของคุณเอง ( @Eric ): blogs.msdn.com/b/ericlippert/archive/2010/09/30/…เพื่อเริ่มดำน้ำ ลงในรายละเอียด มีบทความดีๆอื่น ๆ อีกมากมาย BTW ความแตกต่างในการประมวลผลวัตถุขนาดเล็กในหน่วยความจำ 100,000 ชิ้นแทบจะไม่สังเกตเห็นได้จากค่าใช้จ่ายหน่วยความจำ (~ 2.3 MB) สำหรับคลาส สามารถตรวจสอบได้ง่ายโดยการทดสอบอย่างง่าย
Nick Martyshchenko

23

บางครั้งด้วย structคุณไม่จำเป็นต้องเรียกตัวสร้าง () ใหม่และกำหนดฟิลด์โดยตรงทำให้เร็วกว่าปกติมาก

ตัวอย่าง:

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i].id = i;
    list[i].isValid = true;
}

เร็วกว่าประมาณ 2 ถึง 3 เท่า

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i] = new Value(i, true);
}

ที่Valueเป็นstructที่มีสองช่อง ( idและisValid)

struct Value
{
    int id;
    bool isValid;

    public Value(int i, bool isValid)
    {
        this.i = i;
        this.isValid = isValid;
    }
}

ในทางกลับกันคือรายการที่ต้องย้ายหรือเลือกประเภทค่าทั้งหมดที่การคัดลอกจะทำให้คุณช้าลง เพื่อให้ได้คำตอบที่แน่นอนฉันสงสัยว่าคุณต้องกำหนดโปรไฟล์รหัสของคุณและทดสอบ


เห็นได้ชัดว่าสิ่งต่างๆเร็วขึ้นมากเมื่อคุณมีค่านิยมเหนือขอบเขตดั้งเดิมด้วย
leppie

ฉันขอแนะนำให้ใช้ชื่ออื่นที่ไม่ใช่listเนื่องจากรหัสที่ระบุจะใช้ไม่ได้กับไฟล์List<Value>.
supercat

7

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

เมื่อคุณเรียกตัวดำเนินการใหม่ในคลาสจะได้รับการจัดสรรบนฮีป อย่างไรก็ตามเมื่อคุณสร้างอินสแตนซ์โครงสร้างจะถูกสร้างขึ้นบนสแต็ก สิ่งนี้จะทำให้ได้รับประสิทธิภาพที่เพิ่มขึ้น นอกจากนี้คุณจะไม่ต้องจัดการกับการอ้างอิงถึงอินสแตนซ์ของโครงสร้างเหมือนกับที่คุณทำกับคลาส คุณจะทำงานโดยตรงกับอินสแตนซ์ Struct ด้วยเหตุนี้เมื่อส่งโครงสร้างไปยังเมธอดจึงส่งผ่านค่าแทนการอ้างอิง

เพิ่มเติมที่นี่:

http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx


4
ฉันรู้ว่ามันพูดใน MSDN แต่ MSDN ไม่ได้บอกเล่าเรื่องราวทั้งหมด Stack vs. heap เป็นรายละเอียดการใช้งานและโครงสร้างไม่ได้อยู่บนสแต็กเสมอไป ดูบล็อกล่าสุดได้ที่blogs.msdn.com/b/ericlippert/archive/2010/09/30/…
Anthony Pegram

"... มันถูกส่งผ่านด้วยค่า ... " ทั้งการอ้างอิงและโครงสร้างจะถูกส่งผ่านด้วยค่า (เว้นแต่จะมีการใช้ 'การอ้างอิง') ไม่ว่าจะมีการส่งผ่านค่าหรือการอ้างอิงที่แตกต่างกันหรือไม่กล่าวคือโครงสร้างจะถูกส่งผ่านค่าต่อมูลค่า คลาสอ็อบเจ็กต์จะถูกส่งผ่าน reference-by-value และ ref ที่ทำเครื่องหมาย params pass reference-by-reference
Paul Ruane

10
บทความนั้นทำให้เข้าใจผิดในประเด็นสำคัญหลายประการและฉันได้ขอให้ทีม MSDN แก้ไขหรือลบออก
Eric Lippert

2
@supercat: เพื่อแก้ไขจุดแรกของคุณ: จุดขนาดใหญ่ที่อยู่ในการจัดการรหัสที่ค่าหรือการอ้างอิงให้เป็นค่าที่ถูกเก็บไว้เป็นที่ไม่เกี่ยวข้องส่วนใหญ่ เราได้ทำงานอย่างหนักเพื่อสร้างแบบจำลองหน่วยความจำซึ่งส่วนใหญ่จะช่วยให้นักพัฒนาสามารถอนุญาตให้รันไทม์ทำการตัดสินใจในการจัดเก็บข้อมูลอัจฉริยะในนามของพวกเขาได้ ความแตกต่างเหล่านี้มีความสำคัญมากเมื่อความล้มเหลวในการทำความเข้าใจมีผลกระทบที่เกิดขึ้นเช่นเดียวกับใน C; ไม่มากใน C #
Eric Lippert

1
@supercat: เพื่อกล่าวถึงจุดที่สองของคุณไม่มีโครงสร้างที่ไม่แน่นอนส่วนใหญ่เป็นสิ่งชั่วร้าย ตัวอย่างเช่นโมฆะ M () {S s = new S (); s.Blah (); N (s); }. Refactor to: โมฆะ DoBlah (S s) {s.Blah (); } เป็นโมฆะ M (S s = new S (); DoBlah (s); N (s);} ที่เพิ่งนำเสนอข้อผิดพลาดเนื่องจาก S เป็นโครงสร้างที่ไม่แน่นอนคุณเห็นข้อผิดพลาดทันทีหรือไม่หรือข้อเท็จจริงที่ว่า S คือ โครงสร้างที่เปลี่ยนแปลงได้ซ่อนข้อบกพร่องจากคุณหรือไม่
Eric Lippert

6

อาร์เรย์ของโครงสร้างจะแสดงบนฮีปในบล็อกหน่วยความจำที่อยู่ติดกันในขณะที่อาร์เรย์ของวัตถุจะแสดงเป็นบล็อกการอ้างอิงที่ต่อเนื่องกันโดยมีวัตถุจริงอยู่ที่อื่นบนฮีปดังนั้นจึงต้องใช้หน่วยความจำสำหรับทั้งวัตถุและการอ้างอิงอาร์เรย์ .

ในกรณีนี้ในขณะที่คุณวางไว้ในList<>(และกList<>ถูกสำรองไว้ในอาร์เรย์) จะมีประสิทธิภาพมากขึ้นหน่วยความจำควรใช้โครงสร้าง

(ระวังว่าอาร์เรย์ขนาดใหญ่จะหาทางไปยัง Large Object Heap ซึ่งหากอายุการใช้งานยาวนานอาจส่งผลเสียต่อการจัดการหน่วยความจำของกระบวนการของคุณโปรดจำไว้ว่าหน่วยความจำนั้นไม่ได้เป็นเพียงการพิจารณาเพียงอย่างเดียว)


คุณสามารถใช้refคำสำคัญเพื่อจัดการกับสิ่งนี้
leppie

"อย่างไรก็ตามโปรดระวังอาร์เรย์ขนาดใหญ่นั้นจะหาทางไปยัง Large Object Heap ซึ่งหากอายุการใช้งานยาวนานอาจส่งผลเสียต่อการจัดการหน่วยความจำของกระบวนการของคุณ" - ฉันไม่ค่อยแน่ใจว่าทำไมคุณถึงคิดแบบนั้น? การจัดสรรบน LOH จะไม่ก่อให้เกิดผลเสียใด ๆ ต่อการจัดการหน่วยความจำเว้นแต่ (อาจ) เป็นวัตถุที่มีอายุการใช้งานสั้นและคุณต้องการเรียกคืนหน่วยความจำอย่างรวดเร็วโดยไม่ต้องรอคอลเลคชัน Gen 2
Jon Artus

@ จอนอาร์ทัส: LOH ไม่ได้รับการบดอัด วัตถุใด ๆ ที่มีอายุยืนยาวจะแบ่ง LOH ออกเป็นพื้นที่ของหน่วยความจำว่างก่อนและพื้นที่หลัง จำเป็นต้องมีหน่วยความจำที่ต่อเนื่องกันสำหรับการจัดสรรและหากพื้นที่เหล่านี้ไม่ใหญ่พอสำหรับการจัดสรรหน่วยความจำเพิ่มเติมจะถูกจัดสรรให้กับ LOH (เช่นคุณจะได้รับการแยกส่วน LOH)
Paul Ruane

4

หากพวกเขามีความหมายเชิงคุณค่าคุณควรใช้โครงสร้าง หากมีความหมายอ้างอิงคุณก็ควรใช้คลาส มีข้อยกเว้นซึ่งส่วนใหญ่เอนเอียงไปที่การสร้างคลาสแม้ว่าจะมีความหมายเชิงคุณค่า แต่เริ่มจากตรงนั้น

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

แก้ไข:

ฉันเริ่มพิจารณาคำว่าชั่วร้ายเป็นอันตราย ท้ายที่สุดแล้วการทำให้คลาสไม่แน่นอนเป็นความคิดที่ไม่ดีหากไม่จำเป็นต้องใช้อย่างจริงจังและฉันจะไม่ออกกฎว่าจะใช้โครงสร้างที่เปลี่ยนแปลง เป็นความคิดที่ไม่ดีซึ่งบ่อยครั้งที่เกือบจะเป็นความคิดที่ไม่ดี แต่ส่วนใหญ่แล้วมันไม่ได้ตรงกับความหมายเชิงคุณค่าดังนั้นจึงไม่สมเหตุสมผลที่จะใช้โครงสร้างในกรณีที่กำหนด

อาจมีข้อยกเว้นที่สมเหตุสมผลกับโครงสร้างที่ซ้อนกันส่วนตัวซึ่งการใช้โครงสร้างนั้นทั้งหมดจึงถูก จำกัด ไว้ในขอบเขตที่ จำกัด มาก สิ่งนี้ใช้ไม่ได้กับที่นี่

จริงๆแล้วฉันคิดว่า "มันกลายพันธุ์ดังนั้นมันจึงเป็นสิ่งที่ไม่ดี" ไม่ได้ดีไปกว่าการเกิดขึ้นเกี่ยวกับฮีปและสแต็ก (ซึ่งอย่างน้อยก็มีผลกระทบต่อประสิทธิภาพแม้ว่าจะมีการบิดเบือนข้อมูลบ่อยๆก็ตาม) "มันกลายร่างจึงค่อนข้างจะไม่ได้ทำให้ความรู้สึกที่จะคิดว่ามันมีความหมายค่าจึงเป็นโครงสร้างที่ไม่ดี" เป็นเพียงแตกต่างกันเล็กน้อย แต่ที่สำคัญดังนั้นฉันคิดว่า


3

ทางออกที่ดีที่สุดคือการวัดวัดอีกครั้งจากนั้นวัดเพิ่มเติมบางส่วน อาจมีรายละเอียดเกี่ยวกับสิ่งที่คุณกำลังทำซึ่งอาจทำให้คำตอบที่ง่ายและเข้าใจง่ายเช่น "ใช้โครงสร้าง" หรือ "ใช้คลาส" ยาก


เห็นด้วยกับส่วนการวัด แต่ในความคิดของฉันมันเป็นตัวอย่างที่ตรงไปตรงมาและชัดเจนและฉันคิดว่าอาจจะพูดถึงเรื่องทั่วไปเกี่ยวกับเรื่องนี้ได้ และเมื่อปรากฎบางคนก็ทำ
มิเชล

3

โครงสร้างเป็นหัวใจสำคัญไม่มีอะไรมากไปกว่าการรวมเขตข้อมูล ใน. NET เป็นไปได้ที่โครงสร้างจะ "แสร้งทำเป็น" เป็นวัตถุและสำหรับโครงสร้างแต่ละประเภท NET จะกำหนดประเภทวัตถุฮีปโดยปริยายด้วยเขตข้อมูลและวิธีการเดียวกันซึ่งการเป็นวัตถุฮีปจะทำงานเหมือนวัตถุ . ตัวแปรที่มีการอ้างอิงถึง heap object (โครงสร้างแบบ "บรรจุกล่อง") จะแสดงความหมายอ้างอิง แต่ตัวแปรที่มีโครงสร้างโดยตรงเป็นเพียงการรวมตัวแปร

ฉันคิดว่าความสับสนของโครงสร้างเทียบกับคลาสส่วนใหญ่เกิดจากการที่โครงสร้างมีสองกรณีการใช้งานที่แตกต่างกันมากซึ่งควรมีแนวทางการออกแบบที่แตกต่างกันมาก แต่หลักเกณฑ์ของ MS ไม่ได้แยกความแตกต่างระหว่างกัน บางครั้งมีความจำเป็นในบางสิ่งบางอย่างที่มีพฤติกรรมเหมือนสิ่งของ ในกรณีนี้แนวทางของ MS ค่อนข้างสมเหตุสมผลแม้ว่า "ขีด จำกัด 16 ไบต์" น่าจะเป็นแบบ 24-32 มากกว่าก็ตาม อย่างไรก็ตามบางครั้งสิ่งที่จำเป็นคือการรวมตัวแปร โครงสร้างที่ใช้เพื่อจุดประสงค์นั้นควรประกอบด้วยฟิลด์สาธารณะจำนวนมากและอาจเป็นไฟล์Equalsลบล้างการToStringลบล้างและIEquatable(itsType).Equalsการนำไปใช้งาน โครงสร้างที่ใช้เป็นการรวมเขตข้อมูลไม่ใช่วัตถุและไม่ควรแสร้งทำเป็น จากมุมมองของโครงสร้างความหมายของฟิลด์ไม่ควรมีค่ามากกว่าหรือน้อยไปกว่า "สิ่งสุดท้ายที่เขียนถึงฟิลด์นี้" ความหมายเพิ่มเติมใด ๆ ควรถูกกำหนดโดยรหัสไคลเอ็นต์

ตัวอย่างเช่นถ้า struct ตัวแปรรวมมีสมาชิกMinimumและMaximum, struct Minimum <= Maximumตัวเองควรจะทำสัญญาว่าจะไม่มี โค้ดที่รับโครงสร้างดังกล่าวเป็นพารามิเตอร์ควรทำงานเหมือนกับว่าถูกส่งผ่านแยกกันMinimumและมีMaximumค่า ข้อกำหนดที่Minimumไม่เกินMaximumควรถือเป็นข้อกำหนดที่ว่าMinimumพารามิเตอร์จะต้องไม่มากกว่าการส่งผ่านแยกกันMaximumหนึ่ง

รูปแบบที่เป็นประโยชน์ในการพิจารณาบางครั้งคือการExposedHolder<T>กำหนดคลาสไว้ดังนี้:

class ExposedHolder<T>
{
  public T Value;
  ExposedHolder() { }
  ExposedHolder(T val) { Value = T; }
}

หากมีโครงสร้างการรวมตัวแปรอยู่List<ExposedHolder<someStruct>>ที่ไหนsomeStructก็อาจทำสิ่งต่างๆเช่นmyList[3].Value.someField += 7;แต่การให้myList[3].Valueรหัสอื่นจะทำให้เนื้อหาของValueมันแทนที่จะให้วิธีการแก้ไข ในทางตรงกันข้ามหากใช้ก็จะมีความจำเป็นที่จะต้องใช้List<someStruct> var temp=myList[3]; temp.someField += 7; myList[3] = temp;ถ้าใครใช้ประเภทคลาสที่เปลี่ยนแปลงได้การเปิดเผยเนื้อหาของmyList[3]โค้ดภายนอกจะต้องมีการคัดลอกฟิลด์ทั้งหมดไปยังอ็อบเจ็กต์อื่น ถ้าใครใช้ประเภทคลาสที่ไม่เปลี่ยนรูปหรือโครงสร้าง "สไตล์อ็อบเจ็กต์" ก็จำเป็นต้องสร้างอินสแตนซ์ใหม่ที่เหมือนmyList[3]ยกเว้นsomeFieldที่แตกต่างกันจากนั้นเก็บอินสแตนซ์ใหม่นั้นไว้ในรายการ

หมายเหตุเพิ่มเติมอีกประการหนึ่ง: หากคุณจัดเก็บสิ่งที่คล้ายกันจำนวนมากอาจเป็นการดีที่จะจัดเก็บสิ่งเหล่านี้ไว้ในอาร์เรย์ของโครงสร้างที่อาจซ้อนกันได้โดยควรพยายามรักษาขนาดของแต่ละอาร์เรย์ไว้ระหว่าง 1K ถึง 64K หรือมากกว่านั้น อาร์เรย์ของโครงสร้างมีความพิเศษในการจัดทำดัชนีนั้นจะให้การอ้างอิงโดยตรงไปยังโครงสร้างภายในดังนั้นจึงสามารถพูดว่า "a [12] .x = 5;" แม้ว่าเราจะสามารถกำหนดอ็อบเจกต์ที่คล้ายอาร์เรย์ได้ แต่ C # ไม่อนุญาตให้แชร์ไวยากรณ์ดังกล่าวกับอาร์เรย์



1

จากมุมมอง c ++ ฉันยอมรับว่าการปรับเปลี่ยนคุณสมบัติของโครงสร้างจะช้าลงเมื่อเทียบกับคลาส แต่ฉันคิดว่าพวกเขาจะอ่านได้เร็วขึ้นเนื่องจากโครงสร้างถูกจัดสรรบนสแต็กแทนที่จะเป็นฮีป การอ่านข้อมูลจากฮีปต้องการการตรวจสอบมากกว่าจากสแตก


0

ถ้าคุณไปกับ struct afterall ให้กำจัดสตริงและใช้ขนาดคงที่ถ่านหรือไบต์บัฟเฟอร์

นั่นคือเรื่องของประสิทธิภาพ

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