อะไรคือข้อเสียของการจับคู่ตัวบ่งชี้สำคัญกับ enums?


16

ฉันคิดว่าจะสร้างประเภทที่กำหนดเองสำหรับตัวระบุเช่นนี้:

public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }

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

ดูเหมือนว่า enums ทำงานได้อย่างราบรื่นกับทุกสิ่งที่ฉันต้องการใช้ในเว็บแอปพลิเคชัน. NET ทั่วไป:

  • การกำหนดเส้นทาง MVC ทำงานได้ดี
  • การทำให้เป็นอันดับ JSON ทำงานได้ดี
  • ทุก ๆ ออมที่ฉันสามารถคิดได้ผลดี

ดังนั้นตอนนี้ฉันสงสัยว่า "ทำไมฉันไม่ควรทำเช่นนี้?" นี่เป็นข้อเสียอย่างเดียวที่ฉันนึกได้:

  • มันอาจสร้างความสับสนให้นักพัฒนาอื่น ๆ
  • มันแนะนำความไม่สอดคล้องในระบบของคุณหากคุณมีตัวระบุที่ไม่ครบถ้วน
  • มันอาจต้องใช้การหล่อแบบพิเศษเช่น(CustomerId)42กัน แต่ฉันไม่คิดว่านี่จะเป็นปัญหาเนื่องจากการกำหนดเส้นทาง ORM และ MVC จะส่งค่าของประเภท enum ให้คุณโดยตรง

ดังนั้นคำถามของฉันคือสิ่งที่ฉันหายไป? นี่อาจเป็นความคิดที่ไม่ดี แต่ทำไม



3
นี้เรียกว่า "microtyping" คุณสามารถ google รอบ (เช่นนี้มีไว้สำหรับ Java รายละเอียดจะแตกต่างกัน แต่แรงจูงใจเดียวกัน)
qbd

ฉันพิมพ์คำตอบบางส่วนแล้วลบออกเพราะฉันรู้ว่าฉันคิดผิด ฉันเห็นด้วยกับคุณว่า "นี่อาจเป็นความคิดที่ไม่ดี แต่ทำไม"
user2023861

คำตอบ:


7

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

  • คุณสามารถเพิ่มการแปลงโดยนัยไปยัง int เมื่อคุณคิดถึงสิ่งนี้มันเป็นอีกทิศทางหนึ่งนั่นคือ int -> CustomerId ซึ่งเป็นปัญหาที่ควรได้รับการยืนยันอย่างชัดเจนจากผู้บริโภค
  • คุณสามารถเพิ่มกฎธุรกิจที่ระบุตัวระบุที่ยอมรับได้และอะไรไม่ ไม่ใช่เพียงแค่การตรวจสอบที่อ่อนแอว่า int เป็นค่าบวก: บางครั้งรายการของรหัสที่เป็นไปได้ทั้งหมดจะถูกเก็บไว้ในฐานข้อมูล แต่จะมีการเปลี่ยนแปลงระหว่างการปรับใช้เท่านั้น จากนั้นคุณสามารถตรวจสอบได้อย่างง่ายดายว่า ID ที่ระบุนั้นมีอยู่ต่อผลลัพธ์แคชของการค้นหาที่เหมาะสม ด้วยวิธีนี้คุณสามารถรับประกันได้ว่าแอปพลิเคชันของคุณจะล้มเหลวอย่างรวดเร็วเมื่อมีข้อมูลที่ไม่ถูกต้อง
  • วิธีการในตัวระบุสามารถช่วยคุณในการตรวจสอบการมีอยู่ของฐานข้อมูลที่มีราคาแพงหรือการรับวัตถุ / โดเมนที่สอดคล้องกัน

คุณสามารถอ่านข้อมูลเกี่ยวกับการดำเนินการนี้จากบทความของฟังก์ชั่น C #: ครอบงำจิตใจดั้งเดิม


1
ฉันจะบอกว่าคุณแทบจะไม่ต้องการห่อ int แต่ละอันในคลาส แต่ใน struct
jk

คำพูดที่ดีฉันปรับปรุงคำตอบเล็กน้อย
LukášLánský

3

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

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


1
ข้อได้เปรียบหลักของ enum ก็คือ "ทำงานได้ดี" ในแบบที่คุณต้องการด้วย MVC, การทำให้เป็นอนุกรม, ORMs ฯลฯ ฉันได้สร้างประเภทที่กำหนดเอง (structs และคลาส) ในอดีตและคุณก็จบลงด้วยการเขียนโค้ดมากกว่าคุณ ควรจะต้องทำเพื่อให้เฟรมเวิร์ก / ไลบรารีทำงานกับประเภทที่กำหนดเองของคุณ
default.kramer

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

2

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

ฉันไม่รู้ว่ามันทำงานอย่างไรใน. NET ประสิทธิภาพการทำงานที่ชาญฉลาดเช่นมีค่า enum จำเป็นต้องใส่กล่อง รหัส OTOH ที่ทำงานกับฐานข้อมูลน่าจะเป็น I / O-bound และตัวระบุชนิดบรรจุกล่องจะไม่เป็นคอขวด

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


-1

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

หากคุณแคสต์คุณจะท้าทายเป้าหมายหลักของคุณในการป้องกันไม่ให้กำหนดรหัสประเภท A ให้กับรหัสประเภท B โดยไม่ตั้งใจ ดังนั้น enums จะไม่เป็นประโยชน์กับวัตถุประสงค์ของคุณ

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

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

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


1
ไม่จำเป็นต้องกำหนดจำนวนล่วงหน้าไว้ใน. NET และประเด็นก็คือการหล่อนั้นแทบจะไม่เคยเกิดขึ้นเช่นในกรณีที่public ActionResult GetCustomer(CustomerId custId)ไม่ต้องการนักแสดง - กรอบ MVC จะให้คุณค่า
default.kramer

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

1
ฉันไม่ทราบว่า C # เป็นแบบยืดหยุ่นเกี่ยวกับการใช้ enums แน่นอนว่ามันทำให้ฉันสับสนในฐานะนักพัฒนาที่คุ้นเคยกับความจริง (?) ที่ enums เป็นอย่างดีการแจกแจงค่าที่เป็นไปได้ พวกเขามักจะระบุช่วงของรหัสที่มีชื่อ ดังนั้นตอนนี้ประเภทนี้ "ถูกทารุณกรรม" ในแง่ที่ว่าไม่มีช่วงและไม่มีชื่อเพียงแค่ประเภทที่เหลือ และเห็นได้ชัดว่าประเภทนั้นไม่ปลอดภัยเช่นกัน อีกอย่าง: ตัวอย่างคือแอปพลิเคชันฐานข้อมูลและในบางจุด "enum" ของคุณจะถูกแมปไปยังเขตข้อมูลประเภทหนึ่งซึ่งคุณจะสูญเสียประเภทที่สันนิษฐานไว้ก่อนอย่างปลอดภัย
Martin Maat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.