C # (.NET) ข้อบกพร่องในการออกแบบ [ปิด]


84

ข้อบกพร่องในการออกแบบที่ใหญ่ที่สุดใน C # หรือ. NET Framework โดยทั่วไปมีอะไรบ้าง

ตัวอย่าง: ไม่มีประเภทสตริงที่ไม่เป็นโมฆะและคุณต้องตรวจสอบ DBNull เมื่อดึงค่าจาก IDataReader


ข้อบกพร่องของการออกแบบเหล่านั้นในแง่ใด
Juliet

ด้วย IDataReader คุณสามารถใช้ IsDBNull แทนการตรวจสอบด้วยตนเอง
Marc Gravell

9
Cue Jon Skeet พูดคุยเกี่ยวกับคลาสปิดผนึก;)
ห์

3
มันสวยง่ายต่อการแก้ไข IDataReader กับวิธีขยาย: ดูweblogs.asp.net/skillet/archive/2008/06/18/...
Robert Rossney

@lagerdalek - ฉันจะ +1 ความคิดเห็นนั้นถ้าทำได้; จำได้ดี
Marc Gravell

คำตอบ:


39

ฉันเห็นด้วยอย่างชัดเจนกับโพสต์นี้ (สำหรับผู้ที่ poo-poo ที่ไม่มี ToString มีแอตทริบิวต์ดีบักเกอร์เพื่อจัดเตรียมรูปแบบที่กำหนดเองสำหรับชั้นเรียนของคุณ)

ด้านบนของรายการด้านบนฉันจะเพิ่มคำขอที่สมเหตุสมผลดังต่อไปนี้:

  1. ประเภทการอ้างอิงที่ไม่เป็นโมฆะเป็นส่วนเสริมของประเภทค่าที่เป็นโมฆะ
  2. อนุญาตให้แทนที่ตัวสร้างว่างของโครงสร้าง
  3. อนุญาตให้ข้อ จำกัด ประเภททั่วไประบุคลาสที่ปิดผนึก
  4. ฉันเห็นด้วยกับโปสเตอร์อื่นที่นี่ที่ขอลายเซ็นผู้สร้างโดยพลการเมื่อใช้เป็นข้อ จำกัด นั่นคือ ที่ไหนT : new(string)หรือที่ไหนT : new(string, int)
  5. ฉันเห็นด้วยกับผู้โพสต์คนอื่นที่นี่เกี่ยวกับการแก้ไขเหตุการณ์ทั้งสำหรับรายการเหตุการณ์ที่ว่างเปล่าและในการตั้งค่าพร้อมกัน (แม้ว่าอย่างหลังจะยุ่งยาก)
  6. ตัวดำเนินการควรถูกกำหนดให้เป็นวิธีการขยายและไม่ใช่วิธีการแบบคงที่ของคลาส (หรือไม่ใช่แค่วิธีการแบบคงที่)
  7. อนุญาตคุณสมบัติแบบคงที่และวิธีการสำหรับอินเทอร์เฟซ (Java มีสิ่งนี้ แต่ C # ไม่มี)
  8. อนุญาตให้เริ่มต้นเหตุการณ์ในตัวเริ่มต้นอ็อบเจ็กต์ (อนุญาตเฉพาะฟิลด์และคุณสมบัติเท่านั้น)
  9. เหตุใดไวยากรณ์ "object initializer" จึงใช้ได้เฉพาะเมื่อสร้างออบเจ็กต์ ทำไมไม่ทำให้พร้อมใช้งานเมื่อใดก็ได้เช่น.var e = new Foo(); e { Bar = baz };
  10. แก้ไขพฤติกรรมนับเป็นกำลังสอง ,
  11. คอลเลกชันทั้งหมดควรมีสแนปช็อตที่ไม่เปลี่ยนรูปสำหรับการทำซ้ำ (เช่นการเปลี่ยนคอลเล็กชันไม่ควรทำให้ตัววนซ้ำเป็นโมฆะ)
  12. สิ่งที่เพิ่มเข้ามานั้นง่ายต่อการเพิ่ม แต่ประเภทพีชคณิตแบบปิดที่มีประสิทธิภาพเช่น " Either<T>" นั้นไม่ได้ดังนั้นฉันจึงชอบวิธีการประกาศประเภทพีชคณิตแบบปิดและบังคับใช้การจับคู่รูปแบบที่ละเอียดถี่ถ้วน (โดยทั่วไปแล้วการสนับสนุนชั้นหนึ่งสำหรับรูปแบบผู้เยี่ยมชม แต่ มีประสิทธิภาพมากขึ้น); ดังนั้นเพียงแค่ใช้ enums ขยายด้วยการสนับสนุนการจับคู่รูปแบบที่ละเอียดถี่ถ้วนและไม่อนุญาตกรณีที่ไม่ถูกต้อง
  13. ฉันชอบที่จะสนับสนุนการจับคู่รูปแบบโดยทั่วไป แต่อย่างน้อยที่สุดสำหรับการทดสอบประเภทวัตถุ ฉันก็ชอบไวยากรณ์ของสวิตช์ที่เสนอในโพสต์อื่นที่นี่
  14. ฉันเห็นด้วยกับโพสต์อื่นที่ว่าSystem.IOชั้นเรียนStreamได้รับการออกแบบมาไม่ดี อินเทอร์เฟซใด ๆ ที่ต้องใช้งานบางอย่างเพื่อโยนNotSupportedExceptionเป็นการออกแบบที่ไม่ดี
  15. IListควรจะง่ายกว่าที่เป็นอยู่มาก ในความเป็นจริงนี้อาจเป็นจริงหลายคอลเลกชันของอินเตอร์เฟซที่เป็นรูปธรรมเช่นICollection,
  16. วิธีการมากเกินไปทำให้เกิดข้อยกเว้นเช่น IDictionary เช่น
  17. ฉันต้องการรูปแบบของข้อยกเว้นที่ตรวจสอบแล้วดีกว่าที่มีอยู่ใน Java (ดูการวิจัยเกี่ยวกับระบบประเภทและเอฟเฟกต์สำหรับวิธีการนี้)
  18. แก้ไขกรณีมุมที่น่ารำคาญต่างๆในวิธีการทั่วไปความละเอียดเกินพิกัด ตัวอย่างเช่นลองระบุวิธีการขยายที่มากเกินไปสองวิธีวิธีหนึ่งที่ทำงานกับประเภทการอ้างอิงและอีกวิธีหนึ่งในประเภทโครงสร้างที่ว่างเปล่าและดูว่าการอนุมานประเภทของคุณชอบสิ่งนั้นอย่างไร
  19. ให้วิธีการสะท้อนอย่างปลอดภัยในฟิลด์และชื่อสมาชิกสำหรับอินเทอร์เฟซเช่นINotifyPropertyChangedที่ใช้ชื่อฟิลด์เป็นสตริง คุณสามารถทำได้โดยใช้วิธีการขยายที่ใช้แลมบ์ดาด้วย a MemberExpressionเช่น () => Fooแต่ก็ไม่ค่อยมีประสิทธิภาพ
    • อัปเดต: C # 6.0 ได้เพิ่มตัวnameof()ดำเนินการสำหรับชื่อสมาชิกเดี่ยว แต่ใช้ไม่ได้ในชื่อทั่วไป ( nameof(T) == "T"แทนที่จะเป็นชื่ออาร์กิวเมนต์ประเภทจริง: คุณยังต้องทำtypeof(T).Name)) - และไม่อนุญาตให้คุณรับสตริง "เส้นทาง" เช่นnameof(this.ComplexProperty.Value) == "Value"การ จำกัด การใช้งานที่เป็นไปได้
  20. ช่วยให้ผู้ประกอบการในการเชื่อมต่อและทำให้ทุกประเภทจำนวนหลักดำเนินการIArithmetic; อินเทอร์เฟซตัวดำเนินการที่ใช้ร่วมกันอื่น ๆ ที่เป็นประโยชน์สามารถทำได้เช่นกัน
  21. ทำให้ยากต่อการกลายพันธุ์ฟิลด์ / คุณสมบัติของวัตถุหรืออย่างน้อยที่สุดอนุญาตให้ใส่คำอธิบายประกอบฟิลด์ที่ไม่เปลี่ยนรูปและทำให้ตัวตรวจสอบประเภทบังคับใช้ (เพียงถือว่าเป็นคุณสมบัติที่ได้รับอย่างเดียว fer chrissakes ไม่ใช่เรื่องยาก!); ในความเป็นจริงรวมเขตข้อมูลและคุณสมบัติเข้าด้วยกันอย่างสมเหตุสมผลมากขึ้นเนื่องจากไม่มีประเด็นที่จะมีทั้งสองอย่าง คุณสมบัติอัตโนมัติของ C # 3.0 เป็นขั้นตอนแรกในทิศทางนี้ แต่ไม่ได้ไปไกลพอ
    • อัปเดต: ในขณะที่ C # มีreadonlyคีย์เวิร์ดและ C # 6.0 เพิ่มคุณสมบัติอัตโนมัติแบบอ่านอย่างเดียวแม้ว่าจะไม่เข้มงวดเท่ากับการรองรับภาษาที่แท้จริงสำหรับประเภทและค่าที่ไม่เปลี่ยนรูป
  22. ลดความซับซ้อนของการประกาศตัวสร้าง ฉันชอบวิธีการของ F # แต่อีกโพสต์ที่ต้องการเพียงแค่ "ใหม่" แทนชื่อชั้นก็ดีกว่าอย่างน้อยที่สุด

ก็เพียงพอแล้วสำหรับตอนนี้ฉันคิดว่า สิ่งเหล่านี้คือความระคายเคืองทั้งหมดที่ฉันเคยพบในสัปดาห์ที่ผ่านมา ฉันอาจจะใช้เวลาหลายชั่วโมงถ้าฉันตั้งใจกับมันจริงๆ C # 4.0 กำลังเพิ่มอาร์กิวเมนต์ที่มีชื่อเป็นทางเลือกและค่าเริ่มต้นซึ่งฉันเห็นด้วยอย่างชัดเจน

ตอนนี้สำหรับคำขอที่ไม่มีเหตุผล:

  1. มันจะดีมากจริงๆถ้า C # / CLR สามารถรองรับประเภท constructor polymorphism เช่น ยาสามัญมากกว่ายาชื่อสามัญ

ได้โปรด? :-)


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

1
สำหรับ # 2 โดยทั่วไปจะมีประโยชน์หากโครงสร้างสามารถระบุไม่เพียง แต่ตัวสร้างอื่นที่ไม่ใช่การเติมด้วยศูนย์ แต่ยังรวมถึงตัวสร้างการคัดลอกอื่นที่ไม่ใช่ไบต์สำหรับไบต์ - สำเนา อันที่จริงฉันอยากเห็นเฟรมเวิร์กที่เหมือน. net ซึ่งสามารถทำงานได้ดีในการรับรู้ว่าเอนทิตีอาจมีค่าหรือความหมายอ้างอิงและอนุญาตให้อ็อบเจ็กต์ฮีปประเภทค่าสามารถติดแท็กได้ไม่เปลี่ยนรูปแบบใช้ร่วมกันได้ (ออบเจ็กต์ค่าที่ไม่ได้กำหนดไว้อาจถูกกลายพันธุ์ได้หากโหมดของมันเป็นครั้งแรกที่ CompareExchange จะเปลี่ยนแปลงได้หรืออาจถูกแชร์หากโหมดของมันเป็นครั้งแรกที่ CompareExchange จะแชร์)
supercat

1
คะแนนดีเยี่ยม! สำหรับ # 1 คำอธิบายประกอบระบบชนิดเป็นวิธีแก้ปัญหาทั่วไป แต่ฉันชอบเผยแพร่ข้อ จำกัด ตัวสร้างผ่านตัวแปรประเภทเช่น T: new () Re: # 2 จุดที่ดีเกี่ยวกับตัวสร้างสำเนา แต่ฉันจะพอใจกับตัวสร้างทั่วไปตามบรรทัดที่ฉันอธิบายไว้ข้างต้น ที่ดีไปกว่านั้นคือการกำจัด constructors-as-different-method ทั้งหมดและทำให้เป็นวิธีการคงที่ สิ่งนี้ช่วยให้รูปแบบการก่อสร้างง่ายขึ้นและกว้างขึ้นโดยเฉพาะอย่างยิ่งถ้าเราอนุญาตวิธีการแบบคงที่บนอินเทอร์เฟซ Constructors-as-static-method + static-method-in-interface แก้ # 1 ได้เช่นกัน
naasking

3
# 3: อะไรคือจุดของการใช้คลาสปิดผนึกเป็นพารามิเตอร์ประเภททั่วไปเช่น Foo <T> โดยที่ T: string? # 11: โอเคฉันมีList<T>หนึ่งล้าน Ts คุณเสนอให้ถ่ายภาพรวมอย่างมีประสิทธิภาพได้อย่างไร # 21: ใช้readonlyคำหลัก .... ในขณะที่มีคำแนะนำที่ดีอยู่ที่นี่ แต่ส่วนใหญ่เป็นเพียงคำแนะนำไม่ใช่ข้อบกพร่องในการออกแบบ
Qwertie

2
นี่เป็นคำตอบที่น่าสนใจมาก แต่ฉันคิดว่าเราควรอัปเดตด้วยฟีเจอร์ C # 6 ตัวอย่าง: รายการที่ 19 และ 21 ถูกนำไปใช้ =)
eduardobr

72
  • Reset()วิธีการในการIEnumerator<T>เป็นความผิดพลาด (บล็อก iterator ข้อมูลจำเพาะภาษาแม้กระทั่งเรียกร้องที่ว่านี้พ่นยกเว้น)
  • วิธีการสะท้อนกลับของอาร์เรย์ในมุมมองของเอริคเป็นความผิดพลาด
  • ความแปรปรวนร่วมของอาร์เรย์เป็นและยังคงเป็นสิ่งแปลกประหลาด
    • อัปเดต: C # 4.0 พร้อม. NET 4.0 ได้เพิ่มการสนับสนุนความแปรปรวนร่วม / ความแตกต่างระหว่างอินเทอร์เฟซทั่วไป (เช่นIEnumerable<out T>และFunc<in T, out TResult>แต่ไม่ใช่ประเภทคอนกรีต (เช่นList<T>)
  • ApplicationException ค่อนข้างไม่ชอบ - นั่นเป็นความผิดพลาดหรือไม่?
  • คอลเลกชันที่ซิงโครไนซ์ - เป็นความคิดที่ดี แต่ไม่จำเป็นต้องมีประโยชน์ในความเป็นจริง: โดยปกติคุณต้องซิงโครไนซ์การดำเนินการหลายอย่าง ( Containsจากนั้นAdd) ดังนั้นคอลเล็กชันที่ซิงโครไนซ์การดำเนินการที่แตกต่างกันจึงไม่เป็นประโยชน์ทั้งหมด
    • ปรับปรุง: ประเภทด้วย, , ฯลฯ ที่เพิ่มขึ้นใน .NET Framework 4.0 - แม้ว่าวิธีการที่ยอมรับเป็นตัวแทนโรงงานไม่ได้รับประกันจากโรงงานจะถูกเรียกเพียงครั้งเดียวต่อที่สำคัญSystem.Collections.ConcurrentTryAddGetOrAddTryRemove
  • สามารถใช้งานรูปแบบusing/ lockรูปแบบได้มากขึ้น - บางทีอนุญาตให้แชร์ไวยากรณ์ที่ใช้ซ้ำได้ (ขยายได้?) คุณสามารถจำลองสิ่งนี้ได้โดยการย้อนกลับIDisposableและใช้usingงาน แต่อาจชัดเจนกว่านี้
  • บล็อก iterator: ไม่มีวิธีง่ายๆในการตรวจสอบอาร์กิวเมนต์ล่วงหน้า (แทนที่จะเกียจคร้าน) แน่นอนว่าคุณสามารถเขียนวิธีล่ามโซ่ได้สองวิธี แต่นั่นก็น่าเกลียด
  • ความไม่เปลี่ยนรูปที่ง่ายกว่าจะดี C # 4.0 ช่วยได้นิดหน่อยแต่ยังไม่เพียงพอ
  • ไม่มีการสนับสนุน "พารามิเตอร์ ref-type นี้ไม่สามารถเป็นค่าว่างได้" แม้ว่าสัญญา (ใน 4.0) จะช่วยได้บ้าง แต่ไวยากรณ์เช่นFoo(SqlConnection! connection)(ที่ฉีด null-check / throw) จะดี (ตรงกันข้ามกับint?ฯลฯ )
  • การขาดการสนับสนุนของตัวดำเนินการและตัวสร้างที่ไม่ใช่ค่าเริ่มต้นที่มีชื่อสามัญ C # 4.0 แก้ปัญหานี้ได้เล็กน้อยdynamicหรือคุณสามารถเปิดใช้งานได้เช่นนี้
  • ตัวแปรตัววนซ้ำถูกประกาศนอก while ในส่วนforeachขยายซึ่งหมายความว่า anon-method / lambdas จับตัวแปรเดียวแทนที่จะเป็นตัวแปรเดียวต่อการวนซ้ำ (เจ็บปวดกับ threading / async / etc)

IEnumerable! = IEnumerable <วัตถุ> แปลกจริง
Rauhotz

2
สิ่งที่ IEnumerable คืออาการเมาค้าง 1.1; คุณสามารถใช้. Cast <object> () กับ LINQ ได้อย่างน้อย
Marc Gravell

8
คน BCL กล่าวว่านั่นApplicationExceptionเป็นความผิดพลาด - ไม่มีประโยชน์อย่างที่พวกเขาหวัง พวกเขายังกล่าวว่าควรจะได้รับSystem.Exception abstract
Jay Bazuzi

2
ไม่เป็นโมฆะ: ควรเป็นข้อผิดพลาดในการคอมไพล์ในการส่งผ่านประเภทการอ้างอิงปกติ T ไปยังสิ่งที่ใช้ T ที่ไม่เป็นโมฆะ (เช่นเดียวกับที่คุณไม่สามารถส่ง int? ถึง int) ผ่านไปทางอื่นได้ดีแน่นอน
Jay Bazuzi

1
@ Jon Harrop: IMHO ควรมีการรองรับอาร์เรย์ที่ไม่เปลี่ยนรูปและสำหรับการอ้างอิงอาร์เรย์แบบอ่านอย่างเดียว อาจเป็นไปได้สำหรับตัวแปรอาร์เรย์อื่น ๆ เช่นกัน (เช่น "อาร์เรย์ที่ปรับขนาดได้" (การอ้างอิงทางอ้อม) หรือการอ้างอิงอาร์เรย์แบบออฟเซ็ตและการผูกมัด)
supercat

60

TextWriter เป็นคลาสพื้นฐานของ StreamWriter wtf?

นั่นทำให้ฉันสับสนอย่างมาก


19
+1 ฉันต้องมองมันทุกครั้ง (Whaddaya หมายความว่าฉันไม่สามารถเขียน TextWriter ใหม่ได้ ()?)
Nicholas Piasecki

1
ขอบคุณพระเจ้า ... ฉันคิดว่ามันเป็นแค่ฉัน
IJ Kennedy

เหรอ? เป็นสิ่งที่เขียนข้อความเสมอ แต่มีเพียง StreamWriter เท่านั้นที่ทำเช่นนั้นกับสตรีม ค่อนข้างตรงไปตรงมา
Jon Hanna

4
ชื่อ StreamWriter ไม่ได้ทำให้ความจริงที่ว่ามันเขียนข้อความชัดเจนเพียงพอ IMO ฟังดูแยกกันราวกับว่ามันจะเขียนไบต์และ TextWriter จะเป็นการใช้งานที่แปลกใหม่ซึ่งจะแปลง api ของ (string toWrite) เป็นไบต์ให้คุณ ตอนนี้ถ้ามันถูกเรียกว่า StreamTextWriter แน่นอนมันจะชัดเจนทันที แต่ยาวไปหน่อย :(
Quibblesome

44

ตัวสร้าง C # pet ขนาดเล็ก - ตัวสร้างใช้ไวยากรณ์ C ++ / Java เพื่อให้ตัวสร้างเป็นชื่อเดียวกับคลาส

New()หรือctor()จะดีกว่านี้มาก

และแน่นอนว่าเครื่องมือเช่น coderush ทำให้ปัญหานี้น้อยลงสำหรับการเปลี่ยนชื่อคลาส แต่จาก POV ที่อ่านง่าย New () ให้ความชัดเจนมาก


เอิ่มมันจะรู้ได้อย่างไรว่าคุณกำลังพยายามสร้างอินสแตนซ์ใหม่ของอะไร?
BlueRaja - Danny Pflughoeft

4
@BlueRaja: สก็อตต์หมายถึงการตั้งชื่อตัวสร้างในชั้นเรียน class Foo { new(int j) {i = j} int i; }
dalle

ในขณะที่ฉันเห็นด้วย 100% ว่า ctor () หรือตัวสร้าง () จะดีกว่า (ไม่ใช่ - Newคำหลักที่เป็นตัวพิมพ์ใหญ่ขัดต่อแบบแผน) แต่ฉันลังเลที่จะเรียกมันว่าข้อบกพร่องในการออกแบบ พวกเขาต้องการดึงดูดนักพัฒนา C ++ / Java ที่มีอยู่และการยืมรูปแบบวากยสัมพันธ์เก่า ๆ ที่โง่เขลาจำนวนมากช่วยให้พวกเขาบรรลุเป้าหมายได้
Qwertie

ที่เกี่ยวข้องกับคำถามนี้: stackoverflow.com/questions/32101993/c-sharp-sorted-linkedlistไม่มีทางใด (โดยใช้. NET เท่านั้น) ในการจัดเรียง LinkedList ด้วย MergeSort, bucketsort หรืออัลกอริธึมการเรียงลำดับอื่น ๆ แต่ใช้ linq ซึ่งช้ากว่า มากกว่าการใช้งานแบบเฉพาะกิจ
CoffeDeveloper

29

ฉันไม่เข้าใจว่าคุณทำไม่ได้

โดยที่ T: ใหม่ (U)

ดังนั้นคุณจึงประกาศว่าประเภททั่วไป T มีตัวสร้างที่ไม่ใช่ค่าเริ่มต้น

แก้ไข:

ฉันต้องการทำสิ่งนี้:

public class A 
{
    public A(string text) 
    {

    }
}


public class Gen<T> where T : new(string text) 
{

}

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

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

เนื่องจากไม่สมเหตุสมผลและสับสนในการใช้งานบางอย่าง อย่างไรก็ตามมันจะมีประโยชน์เมื่อทำงานกับวัตถุที่ไม่เปลี่ยนรูป
Pop Catalin

7
โดยทั่วไปการขาดข้อ จำกัด ของสมาชิกเป็นเรื่องที่น่ารำคาญใช่
MichaelGG

3
เอเมนฉันต้องการสิ่งนี้มาตลอด
สตีฟ

20

ฉันแปลกใจจริงๆที่ฉันเป็นคนแรกที่พูดถึงเรื่องนี้:

ADO.NET ชุดข้อมูลที่พิมพ์ไม่แสดงคอลัมน์ที่เป็นโมฆะเป็นคุณสมบัติของประเภทที่ว่างเปล่า คุณควรจะเขียนสิ่งนี้ได้:

int? i = myRec.Field;
myRec.Field = null;

แต่คุณต้องเขียนสิ่งนี้ซึ่งมันโง่มาก:

int? i = (int?)myRec.IsFieldNull() ? (int?)null : myRec.Field;
myRec.SetFieldNull();

นี่เป็นสิ่งที่น่ารำคาญใน. NET 2.0 และตอนนี้มันน่ารำคาญยิ่งกว่าที่คุณต้องใช้ jiggery-pokery เหมือนข้างบนในการสืบค้น LINQ ที่เรียบร้อย

นอกจากนี้ยังน่ารำคาญที่Add<TableName>Rowเมธอดที่สร้างขึ้นนั้นไม่สามารถเข้าใจได้ในทำนองเดียวกันกับความคิดของประเภทที่เป็นโมฆะ ยิ่งไปกว่านั้นเนื่องจากTableAdapterเมธอดที่สร้างขึ้นไม่ใช่

NET ไม่มากนักที่ทำให้ฉันรู้สึกเหมือนที่ทีมนักพัฒนาพูดว่า "โอเคพวกเราสนิทกันมากพอแล้วจัดส่ง!" แต่สิ่งนี้แน่นอน


เห็นด้วยสุดใจ! สิ่งนี้ทำให้ฉันเสียทุกครั้งที่ต้องใช้ (ซึ่งมักจะเป็น) อ๊าก! +1
Eyvind

2
อย่างน้อยที่สุดที่พวกเขาสามารถทำได้คือการสร้างคลาส DataSetV2 ใหม่ (ชื่อเสีย - เพื่อประโยชน์ในการโต้แย้ง) ซึ่งใช้ประเภทค่าที่เป็นโมฆะแทน DBNull ตลอด
Christian Hayter

อย่าลืมความไร้สาระของการต้องการค่าพิเศษDBNull.Valueเมื่อnullตัวมันเองมีค่าเพียงพอที่จะเป็นตัวแทนของ NULL โชคดีที่ LINQ-to-SQL ใช้ null สำหรับ NULL
Qwertie

ที่จริงแล้วความไร้สาระคือหินที่สร้างสิ่งปลูกสร้างไร้สาระทั้งหมดขึ้นมา
Robert Rossney

20
  1. ฉันไม่ใช่แฟนตัวยงของคลาส Stream, StringWriter, StringReader, TextReader, TextWriter ... มันไม่ง่ายเลยว่าคืออะไร
  2. IEnumerable รีเซ็ตทิ้งข้อยกเว้นสำหรับตัวทำซ้ำ ฉันมีส่วนประกอบของบุคคลที่สามซึ่งมักจะเรียกการรีเซ็ตเมื่อฐานข้อมูลต้องการให้ฉันส่งไปยังรายการก่อนเพื่อใช้
  3. Xml Serializer ควรมีองค์ประกอบ IDictionary แบบอนุกรม
  4. ฉันลืมไปโดยสิ้นเชิงเกี่ยวกับ HttpWebRequest & FTP API สิ่งที่ทำให้ฉันเจ็บปวด .... (ขอบคุณสำหรับความคิดเห็นที่นิโคลัสเตือนฉันเรื่องนี้ :-)

แก้ไข
5. สิ่งที่น่ารำคาญอีกประการหนึ่งของฉันคือวิธี System.Reflection.BindingFlags มีการใช้งานที่แตกต่างกันขึ้นอยู่กับวิธีการที่คุณใช้ ใน FindFields เช่น CreateInstance หรือ SetField หมายถึงอะไร? นี่เป็นกรณีที่พวกเขาใช้ความหมายเบื้องหลังการแจงนับนี้มากเกินไปซึ่งทำให้สับสน


1
+1 ฉันต้องค้นหาคลาส XmlTextWriter, TextWriter และอื่น ๆ ทุกครั้ง เช่นเดียวกับสิ่ง HttpWebRequest / Response API ที่ไม่ใช้งานง่ายโดยสิ้นเชิงที่นั่น
Nicholas Piasecki

+ 1-1 = 0: XmlTextWriter และอื่น ๆ ฉันยอมรับว่าเป็นไปไม่ได้ที่จะสรุปอย่างแท้จริงว่าพวกเขามาจากชื่ออะไร HttpWebRequest ฉันไม่เห็นด้วยฉันคิดว่ามันค่อนข้างใช้งานง่าย
AnthonyWJones

สำหรับเขาแต่ละคนฉันคิดว่า ฉันเดาว่าด้วย FTP ฉันคาดหวังว่าสิ่งที่เป็นนามธรรมในระดับที่สูงขึ้นนั้นมีอะไร
JoshBerke

15

ฉันไม่รู้ว่าฉันจะพูดได้ไกลถึงขนาดที่ว่ามันเป็นข้อบกพร่องในการออกแบบ แต่มันจะดีมากถ้าคุณสามารถสรุปการแสดงออกของแลมบ์ดาในลักษณะเดียวกับที่คุณสามารถทำได้ใน VB:

VB:

Dim a = Function(x) x * (x - 1)

ค#

คงจะดีถ้าสามารถทำได้:

var a = x => x * (x - 1);

แทนที่จะต้องทำสิ่งนี้:

Func<int, int> a = x => x * (x - 1);

ฉันรู้ว่ามันไม่ได้ยาวกว่านี้มากนัก แต่ใน Code Golf ทุกตัวละครนับว่าเหี้ย! พวกเขาไม่คำนึงถึงเรื่องนี้เมื่อออกแบบภาษาโปรแกรมเหล่านี้หรือไม่? :)


3
Microsoft ควรนำ Code Golf มาพิจารณาเมื่อออกแบบภาษา?
jrcs3

3
@ เรย์เบิร์นส์: รู้ได้ยังไงใน VB? VB รองรับแล้วความแตกต่างคืออะไร?
BenAlabaster

3
@RayBurns ประเภทอนุมาน? ฉันใช้มันมาตั้งแต่ปี 1989
RD1

3
Lamdas เป็น Homoiconic ใน C # ชิ้นส่วน(int x) => x * (x -1);อาจหมายถึงFunc<int, int>หรืออาจหมายถึงExpression<Func<int, int>>
Scott Weinstein

3
@ BenAlabaster: VB รองรับตัวดำเนินการเลขคณิตที่ถูกผูกไว้ตอนปลาย C # ต้องแก้ไขในเวลาคอมไพล์ มันเป็นความแตกต่างของภาษา ตัวอย่างเช่น VB สามารถเพิ่มสองวัตถุเข้าด้วยกัน C # ไม่สามารถเนื่องจาก+ไม่ได้กำหนดไว้สำหรับobject.
เวียนซ้ำ

14
  1. System.Objectระดับ:

    • Equals และ GetHashCode - ไม่ใช่ทุกคลาสที่สามารถเทียบเคียงได้หรือแฮชได้ควรย้ายไปที่อินเทอร์เฟซ IEquatable หรือ IComparable (หรือคล้ายกัน) อยู่ในใจ

    • ToString - ไม่ใช่ทุกคลาสที่สามารถแปลงเป็นสตริงได้ควรย้ายไปที่อินเทอร์เฟซ IFormattable (หรือคล้ายกัน) อยู่ในใจ

  2. ICollection.SyncRootทรัพย์สิน:

    • ส่งเสริมการออกแบบที่ไม่ดีตัวล็อคภายนอกมักจะมีประโยชน์มากกว่า
  3. Generics ควรมีมาตั้งแต่แรก:

    • System.Collections namespace มีจำนวนมากของการเรียนมากขึ้นหรือน้อยลงและล้าสมัยอินเตอร์เฟซ

1
1. วิธีการเหล่านั้นเป็นเรื่องธรรมดาที่มีการตัดสินว่ากรณี oddball นั้นใช้ได้หรือไม่ว่าจะมีคนเรียก Object.Equals ในชั้นเรียนของคุณหรือไม่? เป็นที่ทราบกันดีว่าอาจมีหรือไม่มีการนำไปใช้และกำหนดให้: IEquatable, IFormattable บนคลาส 99% เป็นเลขคี่
Guvante

1
มีประโยชน์ในการสร้างพจนานุกรมโดยมีอ็อบเจ็กต์ที่ผู้ใช้กำหนดเองเป็นคีย์โดยใช้ค่าความเท่าเทียมกันในการอ้างอิงเริ่มต้นโดยไม่ต้องเพิ่มโค้ดให้กับอ็อบเจ็กต์ที่ผู้ใช้กำหนดอย่างชัดเจนเพื่อจุดประสงค์นั้น ฉันคิดว่า Finalize เป็นขยะที่ใหญ่กว่ามาก (ทางเลือกที่ดีกว่าคือการมีวัตถุที่จะต้องใช้การสรุปขั้นสุดท้ายใช้ iFinalizable และลงทะเบียนอย่างชัดเจนด้วยตนเองเพื่อสรุป) OTOH ควรมีการรองรับ iDisposable โดยธรรมชาติมากขึ้นรวมถึงการเรียก Dispose หากตัวสร้างโยนข้อยกเว้น
supercat

1
@supercat: สิ่งที่จำเป็นคือการอัปเดตEqualityComparer<T>.Defaultอย่างถูกต้อง จากนั้นทั้งสองvar dict = new Dictionary<object, string>(EqualityComparer<object>.Default)และvar dict = new Dictionary<object, string>()จะใช้การเปรียบเทียบอ้างอิง / ความเท่าเทียมกัน
dalle

1
@supercat: สิ่งที่คุณอธิบายเป็นสิ่งที่EqualityComparer<T>.Defaultไม่ ไม่จำเป็นต้องตรวจสอบทุกการค้นหา ตัวเปรียบเทียบเป็นคุณสมบัติของDictionaryอินสแตนซ์และแต่ละตัวจะDictionaryรู้ว่ากำลังใช้ตัวเปรียบเทียบใด
dalle

1
@supercat: พจนานุกรมต้องใช้ประเภททั่วไปที่สุด (เช่นคลาสพื้นฐานทั่วไป) เป็นคีย์การใช้ทั้ง Strings และ DateTime ในพจนานุกรมเดียวกันจะไม่ทำให้เกิดความรู้สึกใด ๆ เว้นแต่จะใช้การเปรียบเทียบอ้างอิงเว้นแต่จะมีการพิสูจน์ว่าผู้ใช้กำหนดว่า คือ. โปรดจำไว้ว่าชื่อของหัวข้อนี้คือ "C # (.NET) Design Flaws"
dalle

12

สิ่งหนึ่งที่ทำให้ฉันหงุดหงิดคือPredicate<T> != Func<T, bool>ความขัดแย้ง ทั้งคู่เป็นผู้รับมอบสิทธิ์ประเภทเดียวกันT -> boolแต่ไม่สามารถใช้งานได้


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

การออกแบบของผู้ได้รับมอบหมายโดยทั่วไปมีข้อบกพร่อง ตัวอย่างเช่นการขาดเหตุการณ์ที่อ่อนแอ (การใช้เหตุการณ์ที่อ่อนแอในฝั่งต้นทางโดยไม่ต้องใช้ความพยายามเป็นพิเศษจากผู้สมัครสมาชิกสามารถทำได้ด้วยการสะท้อนและ ReflectionPermission จำนวนมากเท่านั้นโปรดดูที่codeproject.com/Articles/29922/Weak-Events-in-C ) และความไม่มีประสิทธิภาพที่มาจากข้อกำหนดที่ว่าผู้รับมอบสิทธิ์ต้องเป็นประเภทอ้างอิง (ผู้รับมอบสิทธิ์จะเร็วกว่าและจะใช้หน่วยความจำมากถึง 1/3 ในหลาย ๆ กรณีหากเป็นประเภทค่า - พวกเขาก็จะเป็นคู่ของ ตัวชี้ที่คุณสามารถส่งต่อไปยังกองซ้อนได้)
Qwertie

11

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


คุณควรสามารถ NGEN โปรแกรมของคุณก่อนที่จะรัน
OtávioDécio

ไม่เหมือนกับการลบการอ้างอิงของรันไทม์ คุณบันทึกเฉพาะ JIT แรกที่รันโค้ดของคุณ
Ed S.


ไม่มีเครื่องมือทำให้สับสนที่ทำสิ่งนี้หรือไม่? มันจะฝังกรอบใน exe ของคุณดังนั้นคุณจึงไม่ต้องปรับใช้ ฉันจำชื่อไม่ได้ ... ไม่ใช่ของ PreEmptive ...
JoshBerke

2
Postbuild ของ Xenocode ไม่ทำเช่นนั้นหรือ คงจะดีไม่น้อยถ้า Visual Studio มีวิธีทำ ...
BenAlabaster

11

เรารู้มากเกี่ยวกับสิทธิเทคนิค OO ที่การแยกส่วนการเขียนโปรแกรมตามสัญญาการหลีกเลี่ยงการถ่ายทอดทางพันธุกรรมที่ไม่เหมาะสมการใช้ข้อยกเว้นที่เหมาะสมการเปิด / ปิดหลักความสามารถในการทดแทน Liskov เป็นต้น อย่างไรก็ตาม. Net frameworks ไม่ได้ใช้แนวทางปฏิบัติที่ดีที่สุด

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

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


4
+1 สำหรับการพูดจาโผงผางตามเป้าหมาย ฉันจะเพิ่มสิ่งนี้เข้าไปในคลาสย่อยทุกคลาสการขาดอินเทอร์เฟซสำหรับคลาสพื้นฐานและความลังเลที่จะแก้ไขข้อบกพร่องของเฟรมเวิร์กแม้จะผ่านไปหลายปี
Steven A. Lowe

1
ถ้าเราตัดการไล่ล่าเรากำลังบอกว่า. Net framework นั้นแย่มากจนยากที่จะตัดสินว่าข้อบกพร่องใดที่แย่ที่สุด? ฉันรู้สึกดีขึ้นหลังจากระบายและชื่นชมการโหวตเพิ่มขึ้นเพราะฉันคาดหวังว่าแฟนบอยของ MS จะตะโกนลงมา
Daniel Paull

ฉันไม่ได้ลงคะแนนทั้งสองวิธีและอย่างไรก็ตามฉันลังเลมากที่จะโหวตให้ลดลง แต่ฉันพยายามหาสาเหตุว่าทำไมฉันถึงไม่สนใจ
Mike Dunlavey

2
ฉันคิดว่าคุณกำลังพูดว่า "มันไม่ดีเท่าที่ควร" ซึ่งไม่ใช่คำตอบ ไม่มีอะไรสมบูรณ์แบบ. ระบุข้อมูลเฉพาะ
jcollum

3
ไม่ฉันกำลังบอกว่ามีหลายกรณีที่การออกแบบมีข้อบกพร่องอย่างเห็นได้ชัดจากนั้นเมื่อคุณคิดว่าพวกเขาทำถูกต้องพวกเขาก็ยังทำผิด ตัวอย่างเช่นโพสต์ของฉันในฟอรัม MSDN ที่นี่: social.msdn.microsoft.com/forums/en-US/wpf/thread/…
Daniel Paull

11

ฉันไม่ชอบคำสั่งสวิตช์ C #

ฉันต้องการอะไรเช่นนี้

switch (a) {
  1    : do_something;
  2    : do_something_else;
  3,4  : do_something_different;
  else : do_something_weird; 
}

จึงไม่มีการหยุดพักอีกต่อไป (ลืมง่าย) และความเป็นไปได้ในการคั่นค่าต่างๆ


อันที่จริงฉันคิดว่ามันจะดีกว่านี้ถ้าต้องใช้คำสั่งเดียวหรือบล็อกในวงเล็บปีกกาเหมือนอย่างอื่นใน C # หากไม่มีความสามารถในการล้มเหลวไวยากรณ์การแบ่งปัจจุบันจะค่อนข้างหลบหลีกและไม่ จำกัด ขอบเขตด้วย (AFAIK ฉันอาจไม่รู้)
Tamas Czinege

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

8
ฉันเห็นด้วยกับ OP switchโดยพื้นฐานแล้วใช้งานไม่ได้ในทุกภาษาที่เลียนแบบเวอร์ชันพิการโดยเจตนาของ C (ปรับให้เหมาะสมเพื่อความเร็ว!) VB มีค่าโดยสารที่ดีกว่ามาก แต่ก็ยังคงล้าหลังภาษาที่มีรูปแบบตรงกัน (Haskell, F # …)
Konrad Rudolph

1
tuinostel: บางอย่างเช่นสวิตช์ (a) {กรณีที่ 1 {do_something; } กรณีที่ 2 {do_something_else; }} - นั่นคือการกำจัดคำสั่ง break และกำหนดรหัสบล็อกที่เหมาะสมสำหรับแต่ละกรณี
Tamas Czinege

2
การหยุดพักดูเหมือนเป็นข้อผิดพลาดโดยทั่วไปการคอมไพล์ผิดพลาดหรือไม่? ดูเหมือนว่าจะมีเพียงเพื่อบรรเทาการเปลี่ยนจาก C เป็น C # (aka การสอน devs ที่พวกเขาไม่สามารถผ่านได้โดยอัตโนมัติ)
Guvante

10

เหตุการณ์ใน C # ที่คุณต้องตรวจสอบผู้ฟังอย่างชัดเจน นั่นไม่ใช่ประเด็นของเหตุการณ์ที่จะถ่ายทอดให้ใครก็ตามที่อยู่ที่นั่น? แม้ว่าจะไม่มี?


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

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

วิธีการบางส่วนเป็นทางเลือกที่ใช้ได้ผลในบางกรณี
Robert Harvey

บวกกับการมีเพศสัมพันธ์ทั้งหมดนี้ทำให้เกิด ... MS มี CAB ซึ่งแก้ไขปัญหาทั้งสองนี้ได้ แต่ CAB มีปัญหามากมายในตัวเองเนื่องจากข้อ จำกัด ใน C # (เช่นสตริงแทนที่จะเป็น enums เป็นหัวข้อเหตุการณ์) - ทำไมไม่ทำแบบหลวม ๆ - รวมเหตุการณ์เป็นส่วนหนึ่งของภาษา !?
BlueRaja - Danny Pflughoeft

9

พฤติกรรมที่น่ากลัว (และค่อนข้างมองไม่เห็นสำหรับคนส่วนใหญ่) O (N ^ 2) ของตัวทำซ้ำแบบซ้อน / เรียกซ้ำ iterators

ฉันค่อนข้างเสียใจที่พวกเขารู้เรื่องนี้รู้วิธีแก้ไขแต่ไม่ได้มองว่ามีความสำคัญเพียงพอต่อการรวมบุญ

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

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


นี่เป็นข้อบกพร่องโดยเฉพาะอย่างยิ่งเนื่องจากขัดกับความคาดหวังโดยสัญชาตญาณของพฤติกรรม O และจะดักจับคนจำนวนมาก
oefe

7

บางคลาสใช้อินเทอร์เฟซ แต่ไม่ได้ใช้หลายวิธีของอินเทอร์เฟซนั้นตัวอย่างเช่น Array ใช้ IList แต่ 4 ใน 9 วิธีทำให้ NotSupportedException http://msdn.microsoft.com/en-us/library/system.array_members .aspx


คุณไม่สามารถเปลี่ยนจำนวนองค์ประกอบใน Array ได้ดังนั้นจึงไม่มีอะไรที่ Add, Clear, Insert และ Remove (At) สามารถทำได้ แต่โยน NotSupported ... ในความเป็นจริงฉันคาดหวังว่าการใช้งาน IList ใด ๆ ที่คืนค่าจริงสำหรับ IsFixedSize จะโยนให้กับพวกเขา
CB

@CB ช้าไปหน่อยสำหรับงานปาร์ตี้ฉันเดา :) แต่ถ้า Array ไม่สามารถตอบสนอง "IList" ทำไมต้องใช้มันต่อไป? นั่นเป็นการละเมิด L ในหลักการ SOLID
wingerse

7

สมาชิกคงที่และประเภทที่ซ้อนกันในอินเทอร์เฟซ

นี้จะเป็นประโยชน์อย่างยิ่งเมื่อสมาชิกอินเตอร์เฟซที่มีพารามิเตอร์ของชนิดที่เป็นเฉพาะกับอินเตอร์เฟซ ( เช่นenum ) มันจะเป็นการดีที่จะซ้อนประเภท enum ในประเภทอินเทอร์เฟซ


1
นี่คล้ายกับคำแนะนำอื่น ๆ ของคุณหรือไม่?
RCIX

1
ไม่อันนี้เกี่ยวกับภาษา C # และอีกอันเกี่ยวกับกรอบ ไม่ใช่ทุกคนที่สนใจเกี่ยวกับความแตกต่างดังนั้นขอบอกว่าอันนี้เกี่ยวกับสิ่งที่อนุญาตและอีกเรื่องหนึ่งเกี่ยวกับสิ่งที่มีให้
Jay Bazuzi

6

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


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

@Qwertie: สิ่งที่โง่กว่าคือในช่วงเวลาหนึ่งการเพิ่ม / ลบจะใช้การล็อก แต่ก็ยังไม่ปลอดภัยต่อเธรด
supercat

6
  • null ทุกที่.

  • const ไม่มีที่ไหนเลย

  • API ไม่สอดคล้องกันเช่นการเปลี่ยนผลตอบแทนอาร์เรย์voidแต่ผนวกกับStringBufferผลตอบแทนที่ไม่แน่นอนเดียวกันStringBufferผลตอบแทนที่ไม่แน่นอนเหมือนกัน

  • อินเทอร์เฟซการรวบรวมไม่เข้ากันกับโครงสร้างข้อมูลที่ไม่เปลี่ยนรูปเช่นAddในSystem.Collections.Generic.IList<_>ไม่สามารถกลับผล

  • ไม่ต้องพิมพ์โครงสร้างเพื่อให้คุณเขียน System.Windows.Media.Effects.SamplingMode.BilinearBilinearแทนเพียง

  • ไม่แน่นอน IEnumeratorstructอินเตอร์เฟซที่ใช้งานโดยการเรียนเมื่อมันควรจะเป็นไม่เปลี่ยนรูป

  • ความเท่าเทียมกันและการเปรียบเทียบสินค้าเป็นระเบียบ: คุณได้มีSystem.IComparableและEqualsแต่แล้วคุณได้ยังSystem.IComparable<_>, System.IEquatable,System.Collections.IComparer , System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, และSystem.Collections.Generic.IComparerSystem.Collections.Generic.IEqualityComparer

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


ไม่มีการพิมพ์โครงสร้างใน CLR แต่ดูเหมือนว่าคุณจะมีการพิมพ์โครงสร้างผสมกับการอนุมานประเภทหรือด้วยคุณลักษณะ Ruby ที่เรียกว่า "สัญลักษณ์" การพิมพ์โครงสร้างจะเป็นในกรณีที่ CLR พิจารณาว่า Func <int, bool> และ Predicate <int> เป็นประเภทเดียวกันหรืออย่างน้อยก็แปลงได้โดยปริยาย
Qwertie

พูดถึงการเปรียบเทียบอย่าลืม Comparer <T>!
Qwertie

@Qwertie ฉันอ้างถึงคุณสมบัติภาษาการเขียนโปรแกรมเช่นตัวแปร polymorphic ใน OCaml ไลบรารี LablGL ของ OCaml มีตัวอย่างที่น่าสนใจมากมายของการพิมพ์เชิงโครงสร้างที่มีประโยชน์ในบริบทของกราฟิก ไม่มีอะไรเกี่ยวข้องกับการอนุมานประเภทและเกี่ยวข้องกับสัญลักษณ์เท่านั้น
JD

1
เราจะใช้โครงสร้างที่ไม่เปลี่ยนรูปได้IEnumeratorอย่างไร?
supercat

5

0 แสงจันทร์เป็น enum

ลักษณะเฉพาะของ enum: http://blogs.msdn.com/abhinaba/archive/2007/01/09/more-peculiarites-of-enum.aspx

ดังที่แสดงโดยตัวอย่างที่ดีนี้: http://plus.kaist.ac.kr/~shoh/postgresql/Npgsql/apidocs/Npgsql.NpgsqlParameterCollection.Add_overload_3.html

คำแนะนำของฉันใส่เครื่องหมาย "@" เพื่อประโยชน์:

แทน:

ถ้า ((myVar & MyEnumName.ColorRed)! = 0)

ใช้สิ่งนี้:

ถ้า ((myVar & MyEnumName.ColorRed)! = @ 0)


1
+1 enum เป็นหนึ่งในไม่กี่สิ่งที่ Java ทำถูกต้องในขณะที่ C # ไม่ทำ
BlueRaja - Danny Pflughoeft

5

หากต้องการเพิ่มคะแนนดี ๆ ที่ผู้อื่นทำไว้แล้ว:

  • DateTime.Now == DateTime.Now ส่วนใหญ่ แต่ไม่ใช่ทุกกรณี

  • Stringซึ่งไม่เปลี่ยนรูปมีตัวเลือกมากมายสำหรับการก่อสร้างและการจัดการ แต่StringBuilder(ซึ่งไม่แน่นอน) ไม่ได้

  • Monitor.EnterและMonitor.Exitควรเป็นวิธีการอินสแตนซ์ดังนั้นแทนที่จะสร้างออบเจ็กต์เฉพาะสำหรับการล็อกคุณสามารถสร้าง a ใหม่Monitorและล็อกสิ่งนั้นได้

  • ผู้ทำลายไม่ควรได้รับการตั้งชื่อว่าผู้ทำลาย ข้อมูลจำเพาะของ ECMA เรียกพวกมันว่า finalizers ซึ่งสร้างความสับสนน้อยกว่าสำหรับฝูง C ++ แต่ข้อกำหนดภาษายังคงอ้างถึงพวกเขาว่าเป็นตัวทำลาย


3
DateTime.Nowหนึ่งที่เห็นได้ชัดที่สุดคือการแข่งขันสภาพของโลก แต่ +1 สำหรับส่วนที่เหลือ
BlueRaja - แดนนี่ Pflughoeft

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

4
@Brian Rasmussen: DateTime ตอนนี้เป็นคุณสมบัติที่ค่อนข้างถูกต้องเนื่องจากมีการเปลี่ยนแปลงไม่ใช่โดยการอ่าน แต่เป็นปัจจัยภายนอก หากมีคนอ่านคุณสมบัติเช่น SomeForm.Width จากนั้น - หลังจากที่ผู้ใช้ปรับขนาดฟอร์มแล้วคนหนึ่งอ่านอีกครั้งค่าของการอ่านครั้งที่สองจะแตกต่างกัน แม้ว่าจะเป็นไปได้ว่า DateTime แรกตอนนี้อาจใช้เวลานานพอที่จะดำเนินการซึ่งจะส่งผลต่อค่าที่อ่านโดยวินาที แต่ผลกระทบดังกล่าวจะไม่แตกต่างจากฟังก์ชันอื่น ๆ ที่การดำเนินการใช้เวลาเท่ากัน
supercat

4

วิธีที่เราใช้คุณสมบัติทำให้ฉันระคายเคืองในบางครั้ง ฉันชอบคิดว่ามันเทียบเท่ากับเมธอด getFoo () และ setFoo () ของ Java แต่พวกเขาไม่ได้

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

ด้วยเหตุนี้ฉันจึงปรารถนาเสมอ (นี่ส่วนใหญ่คิดออกมาดัง ๆ ฉันแค่หวังว่าฉันจะทำอะไรแบบนี้ได้) ที่ฉันสามารถขยายไวยากรณ์คุณสมบัติได้ ลองนึกภาพดังนี้:


private string password;

public string Password
{
    // Called when being set by a deserializer or a persistence
    // framework
    deserialize
    {
       // I could put some backward-compat hacks in here. Like
       // weak passwords are grandfathered in without blowing up
       this.password = value;
    }
    get
    {
       if (Thread.CurrentPrincipal.IsInRole("Administrator"))
       {
           return this.password;
       }
       else
       {
           throw new PermissionException();
       }
    }
    set
    {
       if (MeetsPasswordRequirements(value))
       {
           throw new BlahException();
       }
       this.password = value;
    }
    serialize
    {
        return this.password;
    }
}

ฉันไม่แน่ใจว่ามันมีประโยชน์หรือสิ่งที่เข้าถึงสิ่งเหล่านี้จะเป็นอย่างไร แต่ฉันแค่หวังว่าฉันจะทำประโยชน์ได้มากกว่านี้กับคุณสมบัติและปฏิบัติต่อพวกเขาจริงๆเช่น get and set method


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

4

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

public class MyMixin<T> : T
{
    // etc...
}

สามารถใช้เช่นนี้เพื่อขยายสตริงเช่น:

var newMixin = new MyMixin<string>();

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

ขออภัยที่ :-) พูดจาโผงผาง


5
น่าสนใจ แต่ฉันชอบวิธีการขยายมากกว่า หากฉันได้รับไลบรารีที่มีวิธีการขยายสตริงจำนวนมากฉันไม่ต้องการเปลี่ยนการอ้างอิงสตริงทั้งหมดเป็น MyMixin <string> เพื่อรับสิ่งใหม่ เป็นเรื่องเล็กน้อยแน่นอน แต่การเพิ่มวิธีการที่โปร่งใสนั้นเป็นสิ่งที่ทำให้วิธีการขยายนั้นดีมาก
RCIX

BTW คุณรู้หรือไม่ว่ามันใช้งานได้แล้ว?
RCIX

2
ฉันไม่เห็นว่า LINQ สามารถทำงานได้อย่างไร
BlueRaja - Danny Pflughoeft

2
@RCIX: Mixins ฟังดูเหมือนว่าฉันคิดว่าวิธีการขยายควรใช้งานได้ ปัญหาในการสร้างวิธีการขยายโดยปริยายคือหมายความว่าสมาชิกชั้นเรียนจริงจำเป็นต้องมีลำดับความสำคัญเหนือวิธีการขยาย หากมีการกำหนดวิธีการขยาย Graphics.DrawParallelogram (Pen p, Point v1, Point v2, Point v3) และในภายหลังฟังก์ชัน DrawParallelogram จะถูกเพิ่มเข้าไปใน System.Graphics ซึ่งใช้จุดในลำดับที่แตกต่างกันโค้ดที่ใช้วิธีการขยายจะแตกโดยไม่ คำเตือน. BTW จะมีปัญหาหรือไม่โดยใช้จุดสองจุดสำหรับวิธีการขยาย (เช่น object..method ()?)
supercat

3

Microsoft จะไม่แก้ไขข้อบกพร่องที่เห็นได้ชัดในกรอบงานและจะไม่ให้ hooks เพื่อให้ผู้ใช้สามารถแก้ไขได้

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


1
คุณหมายถึงข้อบกพร่องของเฟรมเวิร์กที่ชัดเจน?
Robert Rossney

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


3
  • สามารถเรียกใช้เมธอดส่วนขยายบนตัวแปร null ได้เช่น

    วัตถุ a = null; ก. MyExtMethod (); // สิ่งนี้เรียกได้สมมติว่ามีการกำหนด MyExtMethod ไว้ที่ไหนสักแห่ง

    อาจเป็นประโยชน์ แต่มีความคลุมเครือในหัวข้อข้อยกเว้นการอ้างอิงที่เป็นโมฆะ

  • การตั้งชื่อ 'ข้อบกพร่อง' อย่างหนึ่ง "C" ของ "configuration" ใน System.configuration.dll ควรเป็นตัวพิมพ์ใหญ่

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


3
มีประโยชน์มาก แต่ฉันมีวิธีการขยาย "ThrowIfNull" สำหรับการตรวจสอบพารามิเตอร์ ;-p
Marc Gravell

2
คุณสามารถทำได้? ugh ThrowIfNull เป็นส่วนขยายที่น่าสนใจ แต่ดูเหมือนจะผิด
JoshBerke

1
ใน CLR ธรรมดาคุณสามารถเรียกใช้เมธอดอินสแตนซ์ในการอ้างอิง null และถ้าเมธอดไม่เข้าถึงอ็อบเจ็กต์หรือเป็นฟิลด์การโทรจะไม่ทำให้เกิดข้อยกเว้นการอ้างอิงที่เป็นโมฆะ (คุณไม่สามารถทำได้ใน C # เนื่องจากใช้ callvirt แม้ว่าจะไม่ใช่วิธีเสมือนก็ตาม)
Pop Catalin

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

3
@Will: การจัดการข้อยกเว้นเป็นเรื่องที่น่าเบื่อทั้งใน Java และ. net เนื่องจากกลไกที่ใช้เชื่อมโยงอย่างใกล้ชิดเข้าด้วยกันสามแนวคิดซึ่งค่อนข้างเกี่ยวข้องกัน แต่ก็ค่อนข้างเป็นมุมฉาก: (1) ประเภทของสิ่งที่ผิดพลาด (ข้อผิดพลาดขอบเขตอาร์เรย์, การหมดเวลา I / O ฯลฯ ); (2) ว่าโค้ดบางอย่างควรดำเนินการหรือไม่ (3) ควรพิจารณา "แก้ไข" ปัญหาที่จุดใด พิจารณากิจวัตรที่ควรทำให้วัตถุกลายพันธุ์ด้วยข้อมูลที่อ่านจาก IE ที่ไม่สามารถคำนวณได้ จะเกิดอะไรขึ้นหากมีข้อยกเว้นเกิดขึ้นในการประมวลผลของ IE ที่ไม่สามารถคำนวณได้
supercat

3

เมธอด. พารามิเตอร์. Add () บน SqlCommand ใน V1 ของเฟรมเวิร์กได้รับการออกแบบอย่างน่ากลัว - หนึ่งในโอเวอร์โหลดโดยทั่วไปจะไม่ทำงานหากคุณส่งผ่านพารามิเตอร์ที่มีค่า (int) เป็น 0 ซึ่งทำให้พวกเขาสร้าง วิธีการ. Parameters.AddWithValue () บนคลาส SqlCommand


ฉันเห็นด้วย แต่ฉันคิดว่าคุณหมายถึงวิธี SqlCommand.Parameters.Add ()
Matt Peterson

3
  1. ไม่มีส่วนย่อยของICollection<T>และIList<T>; อย่างน้อยที่สุดก็คืออินเทอร์เฟซคอลเลกชันแบบอ่านอย่างเดียวที่เป็นโควาเรียนIListSource<out T> (ที่มีตัวแจงนับดัชนีและตัวนับ) จะมีประโยชน์อย่างยิ่ง
  2. .NET ไม่สนับสนุนผู้ได้รับมอบหมายที่อ่อนแอ วิธีแก้ปัญหานั้นค่อนข้างเงอะงะและวิธีแก้ปัญหาด้านผู้ฟังเป็นไปไม่ได้ในความไว้วางใจบางส่วน (จำเป็นต้องมี ReflectionPermission)
  3. ห้ามรวมอินเทอร์เฟซทั่วไปได้รับแม้ว่าจะเหมาะสมและไม่ก่อให้เกิดปัญหาก็ตาม
  4. ไม่เหมือนกับใน C ++ ประเภทการส่งคืนโควาเรียไม่ได้รับอนุญาตใน. NET
  5. เป็นไปไม่ได้ที่จะเปรียบเทียบค่าสองประเภทแบบบิตเพื่อความเท่าเทียมกัน ในโครงสร้างข้อมูล " ต่อเนื่อง " ที่ใช้งานได้ฉันกำลังเขียนไฟล์Transform(Sequence<T>, Func<T,T>)ฟังก์ชันที่จำเป็นในการตรวจสอบอย่างรวดเร็วว่าฟังก์ชันนั้นส่งคืนค่าเดียวกันหรือค่าที่แตกต่างกัน หากฟังก์ชันไม่แก้ไขอาร์กิวเมนต์ส่วนใหญ่ / ทั้งหมดลำดับเอาต์พุตสามารถแชร์หน่วยความจำบางส่วน / ทั้งหมดจากลำดับอินพุตได้ หากไม่มีความสามารถในการเปรียบเทียบค่าประเภท T แบบบิตต้องใช้การเปรียบเทียบที่ช้ากว่ามากซึ่งส่งผลเสียต่อประสิทธิภาพอย่างมาก
  6. ดูเหมือนว่า. NET จะไม่รองรับอินเทอร์เฟซเฉพาะกิจ (เช่นที่มีให้ใน Go หรือ Rust) ในลักษณะที่มีประสิทธิภาพ อินเทอร์เฟซดังกล่าวจะช่วยให้คุณสามารถส่งList<T>ไปยังสมมุติฐานIListSource<U>(โดยที่ T: U) แม้ว่าคลาสจะไม่ได้ใช้อินเทอร์เฟซนั้นอย่างชัดเจน มีไลบรารีที่แตกต่างกันอย่างน้อยสาม ไลบรารี (เขียนขึ้นโดยอิสระ) เพื่อจัดหาฟังก์ชันนี้ (แน่นอนว่ามีข้อบกพร่องด้านประสิทธิภาพ - หากวิธีแก้ปัญหาที่สมบูรณ์แบบเป็นไปได้มันจะไม่ยุติธรรมที่จะเรียกว่าข้อบกพร่องใน. NET)
  7. ปัญหาด้านประสิทธิภาพอื่น ๆ : IEnumerator ต้องการการเรียกใช้อินเทอร์เฟซสองครั้งต่อการวนซ้ำ ตัวชี้เมธอดธรรมดา (ผู้รับมอบสิทธิ์แบบเปิดขนาด IntPtr) หรือผู้รับมอบสิทธิ์ที่พิมพ์ค่า (IntPtr * 2) เป็นไปไม่ได้ ไม่สามารถฝังอาร์เรย์ขนาดคงที่ (ประเภท T โดยพลการ) ภายในคลาสได้ ไม่มีWeakReference<T>(คุณสามารถเขียนของคุณเองได้อย่างง่ายดาย แต่จะใช้การร่ายภายใน)
  8. ความจริงที่ว่าประเภทผู้ร่วมประชุมที่เหมือนกันถือว่าเข้ากันไม่ได้ (ไม่มีการแปลงโดยนัย) เป็นสิ่งที่สร้างความรำคาญให้ฉันในบางครั้ง (เช่นPredicate<T>เทียบกับFunc<T,bool>) ฉันมักจะหวังว่าเราจะมีการพิมพ์โครงสร้างสำหรับอินเทอร์เฟซและผู้รับมอบสิทธิ์เพื่อให้เกิดการมีเพศสัมพันธ์ที่หลวมขึ้นระหว่างคอมโพเนนต์เนื่องจากใน. NET นั้นไม่เพียงพอสำหรับคลาสใน DLL อิสระที่จะใช้อินเทอร์เฟซเดียวกัน - พวกเขาต้องแบ่งปันการอ้างอิงร่วมกันไปยังส่วนที่สามด้วย DLL ที่กำหนดอินเทอร์เฟซ
  9. DBNull.Valueมีอยู่แม้ว่าnullจะทำหน้าที่ในจุดประสงค์เดียวกันได้ดีพอ ๆ กัน
  10. C # ไม่มีตัวดำเนินการ ?? =; variable = variable ?? valueคุณต้องเขียน มีอยู่ไม่กี่แห่งใน C # ที่ขาดความสมมาตรโดยไม่จำเป็น ตัวอย่างเช่นคุณสามารถเขียนif (x) y(); else z();(โดยไม่ต้องวงเล็บ) try y(); finally z();แต่คุณไม่สามารถเขียน
  11. เมื่อสร้างเธรดเป็นไปไม่ได้ที่จะทำให้เธรดชายด์สืบทอดค่าเธรดโลคัลจากเธรดหลัก BCL ไม่เพียง แต่ไม่รองรับสิ่งนี้ แต่คุณไม่สามารถใช้งานได้ด้วยตัวเองเว้นแต่คุณจะสร้างเธรดทั้งหมดด้วยตนเอง แม้ว่าจะมีเหตุการณ์สร้างเธรด แต่. NET ก็ไม่สามารถบอกคุณได้ว่า "ผู้ปกครอง" หรือ "ลูก"ของเธรดนั้น ๆ
  12. ความจริงที่ว่ามีแอตทริบิวต์ความยาวที่แตกต่างกันสองแบบสำหรับประเภทข้อมูลที่แตกต่างกัน "ความยาว" และ "จำนวน" เป็นความรำคาญเล็กน้อย
  13. ฉันสามารถดำเนินการต่อไปเรื่อย ๆ เกี่ยวกับการออกแบบ WPF ที่ไม่ดี ... และ WCF (แม้ว่าจะมีประโยชน์มากสำหรับบางสถานการณ์) ก็เต็มไปด้วยหูด โดยทั่วไปความป่องไม่เข้าใจและเอกสารที่ จำกัด ของไลบรารีย่อยรุ่นใหม่ของ BCL ทำให้ฉันลังเลที่จะใช้ สิ่งใหม่ ๆ จำนวนมากอาจจะง่ายกว่าเล็กกว่าใช้งานง่ายกว่าและเข้าใจง่ายกว่ามากขึ้นเอกสารประกอบดีขึ้นใช้ได้กับกรณีการใช้งานที่มากขึ้นเร็วขึ้นและ / หรือพิมพ์มากขึ้น
  14. ฉันมักจะถูกกัดโดยการมีเพศสัมพันธ์ที่ไม่จำเป็นระหว่างตัวรับคุณสมบัติและตัวตั้งค่า: ในคลาสที่ได้รับหรืออินเทอร์เฟซที่ได้รับคุณไม่สามารถเพิ่มตัวตั้งค่าได้เมื่อคลาสพื้นฐานหรืออินเทอร์เฟซพื้นฐานมีเพียง getter หากคุณแทนที่ getter คุณจะไม่ได้รับอนุญาตให้กำหนด setter และคุณไม่สามารถกำหนด setter เป็นเสมือนได้ แต่ getter ไม่ใช่ virtual

ผมเห็นด้วยกับคุณเกี่ยวกับการย่อยของIList<T>แต่ฉันต้องการใช้และIReadableByIndex<out T> IAppendable<in T>สิ่งอื่น ๆ อีกมากมายของคุณเป็นเรื่องที่น่าผิดหวังที่ฉันเห็นด้วยเช่นกัน
supercat

นั่นเป็นชื่อที่ยาวมาก บางทีเราอาจจะประนีประนอมได้IListReader<T>;) - ฉันใช้คำว่า "source" เป็นคำตรงข้ามของ "sink" (อินเทอร์เฟซสำหรับเขียนอย่างเดียว)
Qwertie

อาจจะIListSource<in T>หรือIReadableList<out T>. อาจมีค่าในการมีประเภทอินเทอร์เฟซพื้นฐานรวมถึงวิธีการที่ไม่มีอยู่ในอนุพันธ์ทั้งหมดแม้ว่าฉันคิดว่าบ่อยครั้งที่อินเทอร์เฟซจะค่อนข้างเชี่ยวชาญ ตัวอย่างเช่นอาจมีIList<T>วิธีการปรับขนาดซึ่งอาจได้ผลหรือไม่ได้ผลและIResizableList<T>ใช้วิธีการเดียวกัน แต่รับประกันว่าควรใช้งานได้ แนวทางดังกล่าวอาจมีประโยชน์ในกรณีที่เขตข้อมูลอาจมีการอ้างอิงเพียงรายการเดียวที่ยังหลงเหลืออยู่ไปยังรายการที่ไม่แน่นอนหรือการอ้างอิงที่ใช้ร่วมกันไปยังรายการที่ไม่เปลี่ยนรูป
supercat

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

@supercat นั่นเป็นเพียงเรื่องน่ารำคาญเพราะ C # ไม่ได้มีวิธีที่ง่ายมากในการตรวจสอบว่าอินเทอร์เฟซถูกใช้งานและใช้งานได้ทันที MS ควรเพิ่มคุณสมบัติภาษาเพื่อให้ง่ายขึ้น เทคนิคที่ฉันชอบคือนิพจน์การผูกif (rl:(list as IResizableList<T>) != null) rl.Add(...);แต่มีข้อเสนออื่น ๆ ในฐานะผู้เขียนคอลเลกชั่นและอะแดปเตอร์คอลเลกชันต่างๆสิ่งที่ทำให้ฉันรำคาญคือการเขียนวิธีการหลอกๆมากมายที่ทำให้เกิดข้อยกเว้น ในฐานะแฟนความปลอดภัยฉันไม่อยากได้รับอนุญาตให้เรียกวิธีการที่ผิดกฎหมาย แฟน IntelliSense ฉันไม่ต้องการเห็นพวกเขาอยู่ในรายการ
Qwertie

2

สิ่งหนึ่งที่ฉันออก ticked ใน 1.x คือเมื่อใช้System.Xml.XmlValidatingReaderที่ValidationEventHandler's ValidationEventArgsไม่เปิดเผยพื้นฐานXmlSchemaException(ทำเครื่องหมายภายใน) ซึ่งมีข้อมูลทั้งหมดที่มีประโยชน์เช่นและlinenumber positionแต่คุณคาดว่าจะแยกวิเคราะห์สิ่งนี้ออกจากคุณสมบัติสตริงข้อความหรือใช้การสะท้อนเพื่อขุดออก ไม่ดีนักเมื่อคุณต้องการส่งคืนข้อผิดพลาดที่ผ่านการทำความสะอาดแล้วให้กับผู้ใช้


1

ไม่ชอบที่คุณไม่สามารถใช้ค่าของ enum หนึ่งใน enum อื่นได้เช่น:

    enum Colors { white, blue, green, red, black, yellow }

    enum SpecialColors { Colors.blue, Colors.red, Colors.Yellow } 

2
สิ่งนี้ไม่สมเหตุสมผลด้วยซ้ำ typeof(Color)! = typeof(SpecialColors).
Kirk Woll

10
มันง่ายพอที่จะทำ:enum SpecialColors { blue = Colors.blue, red = Colors.red, yellow = Colors.Yellow }
Trystan Spangler

0

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

จาก MSDN:

  • var สามารถใช้ได้ก็ต่อเมื่อมีการประกาศตัวแปรโลคัลและเริ่มต้นในคำสั่งเดียวกัน ตัวแปรไม่สามารถเริ่มต้นเป็น null หรือไปยังกลุ่มวิธีการหรือฟังก์ชันที่ไม่ระบุชื่อ
  • ไม่สามารถใช้ var กับฟิลด์ที่ขอบเขตคลาส
  • ไม่สามารถใช้ตัวแปรที่ประกาศโดยใช้ var ในนิพจน์การเริ่มต้น กล่าวอีกนัยหนึ่งนิพจน์นี้ถูกกฎหมาย: int i = (i = 20); แต่นิพจน์นี้สร้างข้อผิดพลาดเวลาคอมไพล์: var i = (i = 20);
  • ตัวแปรที่พิมพ์โดยนัยหลายตัวแปรไม่สามารถเริ่มต้นในคำสั่งเดียวกันได้
  • หากประเภทที่มีชื่อว่า var อยู่ในขอบเขตคำสำคัญ var จะแก้ไขเป็นชื่อประเภทนั้นและจะไม่ถือว่าเป็นส่วนหนึ่งของการประกาศตัวแปรโลคัลที่พิมพ์โดยนัย

เหตุผลที่ฉันคิดว่ามันเป็นการใช้งานที่ไม่ดีก็คือพวกเขาเรียกมันว่า var แต่มันก็ยังห่างไกลจากการเป็นตัวแปร มันเป็นเพียงไวยากรณ์ชวเลขที่ไม่ต้องพิมพ์ชื่อคลาสเต็ม (ยกเว้นเมื่อใช้กับ Linq)


ประเภท anon แน่นอน (ใหม่ {... }) ไม่พิมพ์โดยนัย (var)
Marc Gravell

เพียงแค่อ่านสิ่งที่ฉันโพสต์อีกครั้งและมันไม่ถูกต้อง ฉันหมายถึงตัวแปรที่พิมพ์โดยปริยาย
lomaxx

1
Eric Lippert อธิบายว่าทำไมไม่สามารถใช้ var นอกวิธีการได้โดยพื้นฐานแล้วเป็นเพราะมันสร้างกล่องดำแห่งความเป็นไปได้ blogs.msdn.com/ericlippert/archive/2009/01/26/…
Guvante

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