คำแนะนำของ Microsoft ในการใช้คุณสมบัติ C # ใช้ได้กับการพัฒนาเกมหรือไม่


26

ฉันเข้าใจว่าบางครั้งคุณก็ต้องการคุณสมบัติเช่น:

public int[] Transitions { get; set; }

หรือ:

[SerializeField] private int[] m_Transitions;
public int[] Transitions { get { return m_Transitions; } set { m_Transitions = value; } }

แต่ความประทับใจของฉันคือว่าในการพัฒนาเกมถ้าคุณไม่มีเหตุผลที่จะทำอย่างอื่นทุกอย่างควรจะเร็วที่สุด ความประทับใจของฉันจากสิ่งที่ฉันอ่านคือ Unity 3D ไม่แน่ใจว่าจะเข้าถึงแบบอินไลน์ผ่านคุณสมบัติได้ดังนั้นการใช้คุณสมบัติจะส่งผลให้มีการเรียกใช้ฟังก์ชันเพิ่มเติม

ฉันถูกต้องหรือไม่ที่จะเพิกเฉยต่อคำแนะนำของ Visual Studio เพื่อไม่ให้ใช้ช่องสาธารณะ (โปรดทราบว่าเราใช้ในint Foo { get; private set; }กรณีที่มีข้อได้เปรียบในการแสดงการใช้งานที่ต้องการ)

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


34
ตรวจสอบกับผู้สร้างโปรไฟล์เสมอก่อนที่จะเชื่อว่าบางสิ่งบางอย่าง "ช้า" ฉันได้รับการบอกว่า "ช้า" และผู้สร้างโปรไฟล์บอกฉันว่าต้องใช้เวลา 500,000,000 ครั้งในการสูญเสียครึ่งวินาที เนื่องจากมันจะไม่ทำงานมากกว่าหนึ่งร้อยครั้งในเฟรมฉันจึงตัดสินใจว่ามันไม่เกี่ยวข้อง
Almo

5
ฉันพบว่ามีสิ่งที่เป็นนามธรรมเล็กน้อยที่นี่และช่วยในการใช้การเพิ่มประสิทธิภาพระดับต่ำอย่างกว้างขวางยิ่งขึ้น ตัวอย่างเช่นฉันได้เห็นโครงการ C ธรรมดาจำนวนมากโดยใช้รายการที่เชื่อมโยงหลายประเภทซึ่งช้ามากเมื่อเทียบกับอาร์เรย์ที่อยู่ติดกัน (เช่นการสำรองข้อมูลArrayList) เนื่องจาก C ไม่มี generics และโปรแกรมเมอร์ C เหล่านี้น่าจะพบว่าง่ายต่อการใช้งานรายการที่เชื่อมโยงซ้ำกว่าง่ายกว่าการทำเช่นเดียวกันสำหรับArrayListsอัลกอริธึมการปรับขนาด หากคุณคิดว่าการเพิ่มประสิทธิภาพในระดับต่ำดีให้แค็ปซูลมัน!
hegel5000

3
@Almo คุณใช้ตรรกะแบบเดียวกันกับการดำเนินงานที่เกิดขึ้นใน 10,000 แห่งหรือไม่? เพราะนั่นคือการเข้าถึงสมาชิกระดับ เหตุผลคุณควรเพิ่มค่าใช้จ่ายในการปฏิบัติงานเป็น 10K ก่อนตัดสินใจว่าการเพิ่มประสิทธิภาพระดับนั้นไม่สำคัญ และ 0.5 ms เป็นกฎที่ดีกว่าสำหรับเมื่อประสิทธิภาพของเกมของคุณจะถูกทำลายไม่ใช่ครึ่งวินาที ประเด็นของคุณยังคงอยู่ถึงแม้ว่าฉันจะไม่คิดว่าการกระทำที่ถูกต้องชัดเจนเท่าที่คุณต้องการ
piojo

5
คุณมีม้า 2 ตัว แข่งพวกเขา
เสา

@piojo ฉันทำไม่ได้ ความคิดบางอย่างต้องเข้าไปในสิ่งเหล่านี้เสมอ ในกรณีของฉันมันเป็นลูปในรหัส UI หนึ่งอินสแตนซ์ UI, ลูปน้อย, การทำซ้ำน้อย สำหรับบันทึกฉันยกระดับความคิดเห็นของคุณ :)
Almo

คำตอบ:


44

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

ไม่จำเป็น. เช่นเดียวกับในแอพพลิเคชั่นซอฟต์แวร์มีรหัสในเกมที่มีประสิทธิภาพที่สำคัญและรหัสที่ไม่ได้เป็น

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

หากโค้ดถูกเรียกใช้งานทุกๆสองสามวินาทีความสามารถในการอ่านและการบำรุงรักษาจะมีความสำคัญมากกว่าประสิทธิภาพ

ฉันอ่านแล้วว่า Unity 3D ไม่แน่ใจว่าจะเข้าถึงแบบอินไลน์ผ่านทางคุณสมบัติดังนั้นการใช้คุณสมบัติจะส่งผลให้มีการเรียกใช้ฟังก์ชันเพิ่มเติม

ด้วยคุณสมบัติเล็ก ๆ น้อย ๆ ในรูปแบบของint Foo { get; private set; }คุณคุณสามารถมั่นใจได้ว่าคอมไพเลอร์จะเพิ่มประสิทธิภาพของ wrapper คุณสมบัติออก แต่:

  • หากคุณมีการนำไปใช้จริงแล้วคุณจะไม่สามารถแน่ใจได้อีกต่อไป ยิ่งการใช้งานมีความซับซ้อนมากเท่าใดโอกาสที่คอมไพเลอร์ก็จะยิ่งสามารถอินไลน์ได้
  • คุณสมบัติสามารถซ่อนความซับซ้อน นี่คือดาบสองคม ในอีกด้านหนึ่งมันทำให้โค้ดของคุณอ่านและเปลี่ยนแปลงได้มากขึ้น แต่ในทางกลับกันนักพัฒนาซอฟต์แวร์รายอื่นที่เข้าถึงคุณสมบัติของคลาสของคุณอาจคิดว่าพวกเขากำลังเข้าถึงตัวแปรเดียวและไม่ทราบว่าคุณซ่อนโค้ดไว้ด้านหลังของคุณสมบัตินั้นมากแค่ไหน เมื่อสถานที่ให้บริการเริ่มต้นที่จะกลายเป็นราคาแพงคอมพิวเตอร์แล้วฉันมักจะ refactor มันกลายเป็นที่ชัดเจนGetFoo()/ SetFoo(value)วิธีการ: เพื่อบ่งบอกว่ามีมากขึ้นเกิดขึ้นเบื้องหลัง (หรือถ้าฉันต้องแน่ใจมากกว่านี้ว่าคนอื่นได้รับคำใบ้: CalculateFoo()/ SwitchFoo(value))

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

5
"แล้วฉันมักจะ refactor ลงในวิธีการ GetFoo () / SetFoo (ค่า) อย่างชัดเจน:" - จุดดีฉันมักจะย้ายการดำเนินงานหนักออกจากคุณสมบัติเป็นวิธีการ
Mark Rogers

มีวิธียืนยันว่าคอมไพเลอร์ Unity 3D ทำให้การเพิ่มประสิทธิภาพที่คุณพูดถึง (ใน IL2CPP และ Mono builds สำหรับ Android) หรือไม่
piojo

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

9

หากมีข้อสงสัยให้ใช้แนวทางปฏิบัติที่ดีที่สุด

คุณอยู่ในข้อสงสัย


นั่นคือคำตอบที่ง่าย แน่นอนว่าความจริงมีความซับซ้อนมากขึ้น

ก่อนอื่นมีตำนานว่าการเขียนโปรแกรมเกมเป็นพิเศษการเขียนโปรแกรมประสิทธิภาพสูงเป็นพิเศษและทุกอย่างจะต้องเร็วที่สุด ผมเขียนโปรแกรมเกมจัดเป็นการเขียนโปรแกรมตระหนักถึงผลการดำเนินงาน ผู้พัฒนาจะต้องตระหนักถึงข้อ จำกัด ด้านประสิทธิภาพและทำงานภายในสิ่งเหล่านั้น

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

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

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


2

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

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

เหตุผลหลักที่ฉันใช้คุณสมบัติใน 10 ปีของฉันในฐานะโปรแกรมเมอร์ C # มืออาชีพคือการหยุดโปรแกรมเมอร์อื่น ๆ บอกฉันว่าฉันไม่ได้รักษามาตรฐานการเข้ารหัส นี่เป็นการแลกเปลี่ยนที่ดีเพราะแทบจะไม่เคยมีเหตุผลที่ดีที่จะไม่ใช้ทรัพย์สิน


2

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

ด้วยเหตุนี้คุณมักจะได้รับประสิทธิภาพที่ดีขึ้นโดยมีเวกเตอร์และเมทริกซ์ประเภทที่ไม่มีคุณสมบัติ แต่เป็นฟิลด์เปล่า


แนวปฏิบัติที่ดีที่สุดไม่ได้สร้างขึ้นในวัคซีน แม้จะมีลัทธิขนส่งสินค้าอยู่บ้าง แต่โดยทั่วไปแล้ววิธีปฏิบัติที่ดีที่สุดก็อยู่ที่นั่นด้วยเหตุผลที่ดี

ในกรณีนี้เรามีคู่:

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

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

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


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


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

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


ในที่สุดคุณจะได้รับบางสิ่งบางอย่างจากการต่อต้านแนวปฏิบัติที่ดีที่สุดหรือไม่?

สำหรับรายละเอียดของกรณีของคุณ (Unity และ Mono สำหรับ Android) Unity รับค่าโดยการอ้างอิงหรือไม่? หากไม่เป็นเช่นนั้นก็จะคัดลอกค่าอยู่ดีไม่มีประสิทธิภาพเพิ่มขึ้น

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

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

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


1

... ความประทับใจของฉันคือว่าในการพัฒนาเกมถ้าคุณไม่มีเหตุผลที่จะทำอย่างอื่นทุกอย่างควรจะเร็วที่สุดเท่าที่จะเป็นไปได้

:

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

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

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

" ปัญหาที่แท้จริงคือการที่โปรแกรมเมอร์ได้ใช้เวลามากเกินไปไกลกังวลเกี่ยวกับประสิทธิภาพในสถานที่ที่ไม่ถูกต้องและในเวลาที่ผิด ;เพิ่มประสิทธิภาพก่อนกำหนดเป็นรากของความชั่วร้ายทั้งหมด (หรืออย่างน้อยที่สุดของมัน) ในการเขียนโปรแกรม." Donald Knuth, 1974


1

สำหรับสิ่งพื้นฐานเช่นนั้นเครื่องมือเพิ่มประสิทธิภาพ C # จะทำให้ถูกต้องแล้ว ถ้าคุณกังวลเกี่ยวกับมัน (และถ้าคุณกังวลมากกว่า 1% ของรหัสของคุณคุณจะทำผิด ) คุณลักษณะที่ถูกสร้างขึ้นสำหรับคุณ คุณลักษณะนี้[MethodImpl(MethodImplOptions.AggressiveInlining)]เพิ่มโอกาสที่วิธีการจะถูกแทรกอย่างมาก (คุณสมบัติ getters และ setters เป็นวิธีการ)


0

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

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

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

หลักการที่สำคัญที่สุดที่ควรคำนึงถึงเมื่อใช้โครงสร้างคือ:

  1. อย่าส่งผ่านหรือส่งคืนโครงสร้างตามค่าหรือทำให้คัดลอกโดยไม่จำเป็น

  2. หากยึดหลักการ # 1 ไว้โครงสร้างขนาดใหญ่จะทำงานเช่นเดียวกับโครงสร้างขนาดเล็ก

ถ้าAlphablobเป็นโครงสร้างที่มีintเขตข้อมูลสาธารณะ 26 แห่งชื่อ az และตัวให้ทรัพย์สินabที่ส่งคืนผลรวมของเขตข้อมูลaและbเขตข้อมูลนั้นจะได้รับAlphablob[] arr; List<Alphablob> list;รหัสint foo = arr[0].ab + list[0].ab;จะต้องอ่านเขตข้อมูลaและbจากarr[0]แต่จะต้องอ่านทั้งหมด 26 เขตlist[0]แม้ว่ามันจะ ละเว้นทั้งหมดยกเว้นสองรายการ หากต้องการมีคอลเลกชันที่มีลักษณะคล้ายalphaBlobลิสต์ทั่วไปที่สามารถทำงานได้อย่างมีประสิทธิภาพด้วยโครงสร้างที่คล้ายกันเราควรแทนที่เมธอด getter ที่จัดทำดัชนีด้วยเมธอด:

delegate ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
actOnItem<TParam>(int index, ActByRef<T, TParam> proc, ref TParam param);

proc(ref backingArray[index], ref param);ซึ่งก็จะเรียก ได้รับคอลเลกชันดังกล่าวถ้ามีใครมาแทนที่sum = myCollection[0].ab;ด้วย

int result;
myCollection.actOnItem<int>(0, 
  ref (ref alphaBlob item, ref int dest)=>dest = item,
  ref result);

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

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


สวัสดีคุณโพสต์คำตอบของคุณผิดหน้าหรือไม่?
piojo

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

@piojo: การแก้ไขของฉันทำให้ชัดเจนขึ้นหรือไม่
supercat

"จะต้องอ่านรายการทั้งหมด 26 รายการ [0] แม้ว่าจะไม่สนใจทั้งหมดยกเว้นสองรายการ" อะไร? คุณแน่ใจไหม? คุณตรวจสอบ MSIL แล้วหรือยัง C # เกือบผ่านประเภทคลาสโดยอ้างอิง
pjc50

@ pjc50: การอ่านคุณสมบัติให้ผลลัพธ์ตามค่า หากทั้งผู้ทำดัชนีที่ได้รับการจัดทำดัชนีlistและผู้ได้รับทรัพย์สินabนั้นมีทั้งแบบเรียงแถวอาจเป็นไปได้ที่ JITter จะรับรู้ว่ามีเพียงสมาชิกaและbมีความจำเป็น แต่ฉันไม่ทราบว่า JITter รุ่นใดที่ทำสิ่งนั้น
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.