ฉันควรใช้โอเปอเรเตอร์การแปลงประเภทโดยนัยของ C # เมื่อใด


14

ใน C # เราสามารถโอเวอร์โหลดตัวดำเนินการแปลงโดยนัยเช่นนี้ (ตัวอย่างจากMSDN ):

struct Digit
{
    /* ... */
    public static implicit operator byte(Digit d)  // implicit digit to byte conversion operator
    {
        /* ... */
    }
}

ดังนั้นเราจึงสามารถมีประเภทเป็นประเภทค่าที่กำหนดเอง , น่าอัศจรรย์แปลงตัวเองไปอีก (ไม่เกี่ยวข้อง) ประเภทออกจากผู้ชมในความสับสน (จนกว่าพวกเขาจะมองเข้าไปหลังเวทีและเห็นผู้ประกอบการแปลงนัยที่มี)

ฉันไม่ชอบปล่อยให้ใครก็ตามที่อ่านรหัสของฉันในความสับสน ฉันไม่คิดว่าหลายคนทำ

คำถามคือกรณีใช้งานของโอเปอเรเตอร์การแปลงประเภทโดยนัยคืออะไรจะไม่ทำให้โค้ดของฉันเข้าใจยากขึ้น?


1
ว้าว. ที่จริงฉันไม่รู้ว่ามีสิ่งนี้อยู่จริง ไม่ใช่ว่ามันเป็นสิ่งที่ดีที่จะใช้ ฉันรู้ว่าผู้คนรู้สึกรำคาญกับการใช้งานแบบนี้ใน C ++
Katana314

@ Katana314: นั่นไม่ใช่สิ่งที่ผู้คนรำคาญ แต่เกี่ยวกับคนที่เพิ่มเกิน (ไม่ว่าจะเป็นโอเปอเรเตอร์, ฟังก์ชั่นการแปลง, คอนสตรัคเตอร์, ฟังก์ชั่นฟรีหรือฟังก์ชั่นสมาชิก) ที่มีพฤติกรรมที่น่าประหลาดใจ
Deduplicator

ฉันแนะนำให้คุณอ่าน "โอเปอเรเตอร์เกินพิกัด" ใน C ++ โดยเฉพาะโอเปอเรเตอร์ "แคสติ้ง" ฉันสงสัยว่าหลายข้อโต้แย้งเดียวกันสำหรับ / ต่อต้านเหมือนกันยกเว้นการอภิปรายที่เกิดขึ้นสามครั้งตราบใดที่ C # มีอยู่กับการอ่านมากขึ้น

คำตอบ:


18

ฉันจะแนะนำเฉพาะการแปลงโดยนัยระหว่างประเภทที่แสดงค่าโดยประมาณในวิธีที่ต่างกัน ตัวอย่างเช่น

  • ประเภทสีที่แตกต่างชอบRGB, HSL, และHSVCMYK
  • หน่วยต่าง ๆ สำหรับปริมาณทางกายภาพเดียวกัน ( Metervs Inch)
  • ระบบพิกัดที่แตกต่างกัน (ขั้วโลก vs คาร์ทีเซียน)

อย่างไรก็ตามมีแนวทางที่ชัดเจนบางข้อที่ระบุว่าไม่เหมาะสมที่จะกำหนดการแปลงที่แน่นอน:

  • หากการแปลงทำให้เกิดการสูญเสียความแม่นยำหรือช่วงอย่างมีนัยสำคัญการแปลงนั้นไม่ควรเป็นนัย (เช่น: จาก float64 ถึง float32 หรือจาก long เป็น int)
  • หากการแปลงสามารถส่งInvalidCastข้อยกเว้น( ) ได้แสดงว่าไม่ควรมีการบอกเป็นนัย
  • หากการแปลงทำให้เกิดการจัดสรรฮีปในแต่ละครั้งที่ดำเนินการแสดงว่าไม่ควรมีการบอกเป็นนัย ๆ
  • หากการแปลงไม่ใช่การO(1)ดำเนินการแสดงว่าไม่ควรเกิดขึ้นโดยปริยาย
  • หากประเภทแหล่งที่มาหรือประเภทเป้าหมายนั้นไม่แน่นอนการแปลงจะไม่เป็นนัย
  • หากการแปลงขึ้นอยู่กับบริบทบางอย่าง (ฐานข้อมูลการตั้งค่าวัฒนธรรมการกำหนดค่าระบบไฟล์ ฯลฯ ) ก็ไม่ควรที่จะบอกเป็นนัย ๆ

ทีนี้สมมติว่าผู้ให้บริการ Conversion ของคุณf: T1 -> T2ไม่ละเมิดกฎใด ๆ ข้างต้นจากนั้นพฤติกรรมดังต่อไปนี้บ่งบอกว่าการแปลงนั้นอาจเป็นนัย:

  • หากแล้วa == bf(a) == f(b)
  • หากแล้วa != bf(a) != f(b)
  • หากแล้วa.ToString() == b.ToString()f(a).ToString() == f(b).ToString()
  • ฯลฯ สำหรับการดำเนินงานอื่น ๆ ที่มีการกำหนดทั้งในและT1T2

ตัวอย่างทั้งหมดของคุณอาจสูญเสีย ไม่ว่าพวกเขาจะแน่นอนพออยู่แล้ว ...
Deduplicator

ใช่ฉันรู้ว่า :-) ฉันไม่สามารถคิดถึงคำว่า "lossy" ที่ดีกว่าได้ สิ่งที่ฉันหมายถึง "lossy" คือการแปลงที่ช่วงหรือความแม่นยำลดลงอย่างมาก เช่นจาก float64 ถึง float32 หรือจาก long ถึง int
Elian Ebbing

ฉันคิดว่า! = b => f (a)! = f (b) อาจไม่สามารถใช้ได้ มีฟังก์ชั่นมากมายที่อาจส่งคืนค่าเดียวกันสำหรับอินพุทต่าง ๆ floor () และ ceil () ที่แตกต่างกันในด้านคณิตศาสตร์
cdkMoose

@cdkMoose คุณพูดถูกและนั่นก็เป็นเหตุผลว่าทำไมฉันถึงเห็นคุณสมบัติเหล่านี้มากขึ้นว่าเป็น "คะแนนโบนัส" ไม่ใช่กฎ คุณสมบัติที่สองหมายถึงฟังก์ชั่นการแปลงนั้นเป็นแบบฉีด กรณีนี้มักเกิดขึ้นเมื่อคุณแปลงเป็นประเภทที่มีช่วงที่ใหญ่กว่าอย่างเข้มงวดเช่นจาก int32 เป็น int64
Elian Ebbing

@cdkMoose ในทางกลับกันคุณสมบัติแรกเพียงแค่ระบุว่าสองค่าในคลาสสมมูลเดียวกันของT1(โดยนัยโดย==ความสัมพันธ์บนT1) จะแมปกับค่าสองค่าภายในคลาสสมมูลเดียวกันของT2เสมอ ตอนนี้ฉันคิดเกี่ยวกับมันฉันเดาว่าคุณสมบัติแรกควรจะเป็นจริงสำหรับการแปลงโดยนัย
Elian Ebbing

6

คำถามคือกรณีใช้งานของโอเปอเรเตอร์การแปลงประเภทโดยนัยคืออะไรจะไม่ทำให้โค้ดของฉันเข้าใจยากขึ้น?

เมื่อประเภทไม่เกี่ยวข้อง (กับโปรแกรมเมอร์) มีสถานการณ์ (หายาก) ที่คุณมีสองประเภทที่ไม่เกี่ยวข้อง (เท่าที่เกี่ยวข้องกับรหัส) ที่เกี่ยวข้องจริง ๆ (เท่าที่โดเมนหรือโปรแกรมเมอร์ที่เหมาะสม) เกี่ยวข้อง

ตัวอย่างเช่นบางรหัสที่จะทำการจับคู่สตริง สถานการณ์ทั่วไปคือการจับคู่สตริงตัวอักษร แทนที่จะเป็นการโทรIsMatch(input, new Literal("some string"))การแปลงโดยนัยช่วยให้คุณกำจัดพิธีดังกล่าว - เสียงรบกวนในรหัส - และมุ่งเน้นไปที่ตัวอักษรสตริง

โปรแกรมเมอร์ส่วนใหญ่จะเห็นIsMatch(input, "some string")และเข้าใจได้อย่างรวดเร็วว่าเกิดอะไรขึ้น มันทำให้รหัสของคุณชัดเจนขึ้นที่ไซต์การโทร กล่าวโดยสรุปคือทำให้เข้าใจง่ายขึ้นเล็กน้อยว่าเกิดอะไรขึ้นโดยเสียค่าใช้จ่ายเล็กน้อยในสิ่งที่เกิดขึ้น

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

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


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