เมื่อวางแผนโปรแกรมของฉันฉันมักจะเริ่มต้นด้วยความคิดอย่าง:
ทีมฟุตบอลเป็นเพียงรายชื่อผู้เล่นฟุตบอล ดังนั้นฉันควรเป็นตัวแทนด้วย:
var football_team = new List<FootballPlayer>();
การเรียงลำดับของรายการนี้แสดงถึงลำดับที่ผู้เล่นแสดงไว้ในบัญชีรายชื่อ
แต่ฉันตระหนักในภายหลังว่าทีมยังมีคุณสมบัติอื่น ๆ นอกเหนือจากรายชื่อผู้เล่นที่ต้องบันทึกไว้ ตัวอย่างเช่นคะแนนรวมที่ดำเนินการอยู่ในฤดูกาลนี้งบประมาณปัจจุบันสีสม่ำเสมอstring
ชื่อตัวแทนของทีม ฯลฯ
ดังนั้นฉันคิดว่า:
โอเคทีมฟุตบอลก็เหมือนกับรายการของผู้เล่น แต่นอกจากนี้ยังมีชื่อ (a
string
) และคะแนนรวมทั้งหมด (anint
) .NET ไม่มีคลาสสำหรับเก็บทีมฟุตบอลดังนั้นฉันจะสร้างคลาสของตัวเอง โครงสร้างที่มีอยู่ที่คล้ายกันและเกี่ยวข้องมากที่สุดคือList<FootballPlayer>
ดังนั้นฉันจะสืบทอดจากมัน:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
แต่มันกลับกลายเป็นว่าแนวทางในการพูดว่าคุณไม่ควรสืบทอดมาจาก List<T>
ฉันสับสนอย่างละเอียดโดยแนวทางนี้สองประการ
ทำไมจะไม่ล่ะ?
เห็นได้ชัดว่ามีการเพิ่มประสิทธิภาพอย่างใดเพื่อให้ได้ประสิทธิภาพList
งั้นเหรอ ฉันจะทำให้เกิดปัญหาประสิทธิภาพการทำงานถ้าฉันขยายList
? จะเกิดอะไรขึ้น
เหตุผลที่ผมเคยเห็นก็คือการที่List
ให้บริการโดยไมโครซอฟท์และผมสามารถควบคุมมันไม่ได้ดังนั้นฉันไม่สามารถเปลี่ยนได้ในภายหลังหลังจากเปิดเผย "ประชาชน API" แต่ฉันพยายามเข้าใจสิ่งนี้ API สาธารณะคืออะไรและทำไมฉันจึงควรใส่ใจ หากโครงการปัจจุบันของฉันไม่ได้และไม่น่าจะมี API สาธารณะนี้ฉันจะเพิกเฉยต่อแนวทางนี้ได้อย่างปลอดภัยหรือไม่? หากฉันได้รับช่วงต่อจากนี้List
และกลายเป็นว่าฉันต้องการ API สาธารณะฉันจะมีปัญหาอะไรบ้าง
ทำไมมันถึงสำคัญ รายการคือรายการ สิ่งที่อาจเปลี่ยนแปลงได้? ฉันอาจต้องการเปลี่ยนแปลงอะไร
และสุดท้ายถ้า Microsoft ไม่ต้องการให้ฉันรับช่วงต่อList
ทำไมพวกเขาถึงไม่ทำคลาสsealed
?
ฉันควรจะใช้อะไรอีก
เห็นได้ชัดว่าสำหรับคอลเลกชันที่กำหนดเอง, ไมโครซอฟท์ได้จัดให้มีระดับที่ควรจะขยายแทนCollection
List
แต่คลาสนี้เปลือยมากและไม่มีสิ่งที่มีประโยชน์มากมายเช่นAddRange
เช่น คำตอบของ jvitor83ให้เหตุผลด้านประสิทธิภาพสำหรับวิธีการเฉพาะนั้น แต่วิธีการนั้นช้าAddRange
ไม่ดีกว่าไม่AddRange
?
การสืบทอดจากCollection
เป็นวิธีการทำงานมากกว่าการสืบทอดจากList
และฉันไม่เห็นประโยชน์ แน่นอนว่า Microsoft จะไม่บอกให้ฉันทำงานพิเศษโดยไม่มีเหตุผลดังนั้นฉันจึงอดไม่ได้ที่จะรู้สึกว่าฉันเข้าใจผิดบางอย่างและการรับมรดกCollection
ไม่ใช่วิธีแก้ปัญหาที่เหมาะสมสำหรับปัญหาของฉัน
ผมเคยเห็นข้อเสนอแนะต่าง ๆ IList
เช่นการดำเนินการ แค่ไม่. นี่คือโค้ดบรรทัดสำเร็จรูปหลายสิบบรรทัด
สุดท้ายบางคนแนะนำให้ห่อList
ในบางสิ่ง:
class FootballTeam
{
public List<FootballPlayer> Players;
}
มีสองปัญหากับสิ่งนี้:
มันทำให้รหัสของฉัน verbose โดยไม่จำเป็น ตอนนี้ผมต้องเรียกแทนเพียง
my_team.Players.Count
my_team.Count
โชคดีที่มี C # ฉันสามารถกำหนดตัวจัดทำดัชนีเพื่อให้การทำดัชนีโปร่งใสและส่งต่อวิธีการทั้งหมดของภายในList
... แต่นั่นคือรหัสจำนวนมาก! ฉันจะได้อะไรจากการทำงานทั้งหมดแค่ธรรมดา ๆ ก็ไม่สมเหตุสมผล ทีมฟุตบอลไม่มีรายชื่อผู้เล่น "มี" มันเป็นรายการของผู้เล่น คุณไม่พูดว่า "John McFootballer ได้เข้าร่วมกับผู้เล่นของ SomeTeam" คุณพูดว่า "John ได้เข้าร่วม SomeTeam" คุณไม่ได้เพิ่มตัวอักษรใน "ตัวอักษรของสตริง" คุณเพิ่มตัวอักษรลงในสตริง คุณไม่เพิ่มหนังสือลงในหนังสือของห้องสมุด แต่เพิ่มหนังสือลงในห้องสมุด
ฉันรู้ว่าสิ่งที่เกิดขึ้น "ภายใต้ประทุน" อาจกล่าวได้ว่าเป็น "การเพิ่ม X เข้ากับรายการภายในของ Y" แต่นี่ดูเหมือนจะเป็นวิธีคิดที่ไม่โต้ตอบเกี่ยวกับโลก
คำถามของฉัน (สรุป)
C # วิธีที่ถูกต้องในการเป็นตัวแทนของโครงสร้างข้อมูลซึ่ง "ตรรกะ" (กล่าวคือ "เพื่อจิตใจมนุษย์") เป็นเพียงlist
ของที่things
มีระฆังและนกหวีดไม่กี่?
สืบทอดมาจากที่List<T>
ยอมรับไม่ได้เสมอ? ยอมรับได้เมื่อไหร่? ทำไม / ทำไมไม่ โปรแกรมเมอร์ต้องพิจารณาอะไรเมื่อตัดสินใจว่าจะสืบทอดจากList<T>
หรือไม่
string
จะต้องทำทุกอย่างobject
สามารถทำและอื่น ๆ