ข้อดีของภาษา C# เมื่อเทียบกับภาษาอื่น ๆ ตอนที่ 5

มีบิลด์อิน (Built-in) ไทป์มากกว่า
ชนิดข้อมูลในภาษาซีชาร์ปแบ่งออกเป็นสองประเภทคือเวลูไทป์และรีเฟอร์เรนซ์ไทป์ (reference type) ข้อแตกต่างระหว่างสองแบบนี้คือ ชนิดข้อมูลแบบเวลูไทป์ ตัวแปรจะเก็บข้อมูลไว้โดยตรง ขณะที่รีเฟอร์เรนซ์ไทป์ตัวแปรจะไม่เก็บข้อมูล แต่เก็บค่าอ้างอิงไปยังข้อมูลหรืออพเจ็กต์ ดังนั้นในกรณีรีเฟอร์เรนซ์ไทป์เราสามารถมีตัวแปรสองตัวอ้างไปยังข้อมูลชิ้นเดียวกันได้ ในขณะที่เวลูไทป์เราจะมีตัวแปรสองตัวอ้างถึงข้อมูลชิ้นเดียวกันไม่ได้
- แบบบูลีน (bool)
- กลุ่มจำนวนเต็มมีเครื่องหมาย (Signed integral)
- sbyte
- short
- int
- long
- กลุ่มจำนวนเต็มไม่มีเครื่องหมาย (Unsigned integral)
- byte
- ushort
- uint
- ulong
- กลุ่มมีทศนิยม (Floating point)
- float
- double
- แบบตัวหนึ่งตัวอักษร (char)
- แบบทศนิยมความละเอียดสองเท่า (decimal)
ชนิดข้อมูลแบบบูลีน
มีความเป็นไปได้เพียงสองอย่างคือจริง (true) และเท็จ (false) หากประกาศตัวแปรโดยไม่กำหนดค่าจะมีค่าโดยปริยายเป็นเท็จ ปรกติเราจะใช้บูลีนเพื่อตรวจสอบสถานะภายในคำสั่ง if หรือคำสั่งในกลุ่มวนซ้ำ ในโค้ดตัวอย่างบรรทัดที่ 1 ใช้คำสั่ง using เพื่อนำเข้าเนมสเปส System เพราะมีนิยามของชนิดข้อมูลแบบบูลีนอยู่ในนั้น คำสั่งบรรทัดที่ 4 ถึง 11 คือนิยามคลาส BooleanExample เพื่อแสดงวิธีใช้งานตัวแปรที่มีชนิดข้อมูลแบบบูลีน บรรทัด 8 ประกาศตัวแปรชนิดบูลีน บรรทัด 9 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ true
ชนิดข้อมูลแบบจำนวนเต็ม
- บรรทัด 8 ประกาศตัวแปรชนิด sbyte ซึ่งมีขนาดแปดบิต เก็บค่าได้ระหว่าง -128 ถึง 127 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 9 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 23
- บรรทัด 10 ประกาศตัวแปรชนิด short ซึ่งมีขนาดสิบหกบิต เก็บค่าได้ระหว่าง -32,768 ถึง 32,768 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 11 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ -1109
- บรรทัด 12 ประกาศตัวแปรชนิด int ซึ่งมีขนาดสามสิบสองบิต เก็บค่าได้ระหว่าง -2,147,483,648 ถึง 2,147,483,648 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 13 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 51092
- บรรทัด 14 ประกาศตัวแปรชนิด long ซึ่งมีขนาดหกสิบสี่บิต เก็บค่าได้ระหว่าง -9,223,372,036,854,775,808 ถึง 9,223,372,036,854,775,808 และมีค่าโดยปริยายเป็น 0L บรรทัด 15 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ -7091821871 โปรดสังเกตการใส่ตัวอักษร L ไว้หลังตัวเลขที่กำหนดค่าในบรรทัดที่ 14 ซึ่งทำหน้าที่บอกให้คอมไพเลอร์รู้ว่าเป็นค่าแบบ long
ชนิดข้อมูลแบบจำนวนเต็ม ไม่มีเครื่องหมาย
- บรรทัด 8 ประกาศตัวแปรชนิด byte ซึ่งมีขนาดแปดบิต เก็บค่าได้ระหว่าง 0 ถึง 255 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 9 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 62
- บรรทัด 10 ประกาศตัวแปรชนิด ushort ซึ่งมีขนาดสิบหกบิต เก็บค่าได้ระหว่าง 0 ถึง 65,535 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 11 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 42019
- บรรทัด 12 ประกาศตัวแปรชนิด uint ซึ่งมีขนาดสามสิบสองบิต เก็บค่าได้ระหว่าง 0 ถึง 4,294,967,295 และมีค่าโดยปริยายเป็นศูนย์ บรรทัด 13 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 1151092
- บรรทัด 14 ประกาศตัวแปรชนิด ulong ซึ่งมีขนาดหกสิบสี่บิต เก็บค่าได้ระหว่าง 0 ถึง 18,446,744,073,709,551,615 และมีค่าโดยปริยายเป็น 0L บรรทัด 15 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 17091821871 โปรดสังเกตการใส่ตัวอักษร L ไว้หลังตัวเลขที่กำหนดค่าในบรรทัดที่ 14 ซึ่งทำหน้าที่บอกให้คอมไพเลอร์รู้ว่าเป็นค่าแบบ long
สุดท้ายคือตัวอย่างบิลด์อินไทป์อีกสี่แบบคือ float, double, char และ decimal
- ในโค้ดตัวอย่างบรรทัดที่ 1 ใช้คำสั่ง using เพื่อนำเข้าเนมสเปส System เพราะมีนิยามของชนิดข้อมูลจำนวนเต็มแบบไม่มีเครื่องหมายทั้งหมดอยู่ในนั้น คำสั่งบรรทัดที่ 4 ถึง 19 คือนิยามคลาส MoreTypeExample เพื่อแสดงวิธีใช้งานตัวแปรที่มีชนิดข้อมูลสี่แบบแบบดังที่กล่าวมาข้างต้น
- บรรทัด 8 ประกาศตัวแปรชนิด float ซึ่งมีขนาดสามสิบสองบิต เก็บค่าตัวเลขทศนิยมได้ระหว่าง 1.5 × 10^−45 ถึง 3.4 × 10^38 มีความละเอียดของทศนิยมเจ็ดหลัก และมีค่าโดยปริยายเป็น 0.0F บรรทัด 9 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 43.27 โปรดสังเกตการใส่ตัวอักษร F ไว้หลังตัวเลขที่กำหนดค่าในบรรทัดที่ 8 ซึ่งทำหน้าที่บอกให้คอมไพเลอร์รู้ว่าเป็นค่าแบบ float
- บรรทัด 10 ประกาศตัวแปรชนิด double ซึ่งมีขนาดใหญ่กว่า float สองเท่าคือหกสิบสี่บิต เก็บค่าตัวเลขทศนิยมได้ระหว่าง 5.0 × 10^−324 ถึง 1.7 × 10^308 มีความละเอียดของทศนิยมสิบห้าหลัก และมีค่าโดยปริยายเป็น 0.0D บรรทัด 11 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ -11092.53 โปรดสังเกตการใส่ตัวอักษร D ไว้หลังตัวเลขที่กำหนดค่าในบรรทัดที่ 10 ซึ่งทำหน้าที่บอกให้คอมไพเลอร์รู้ว่าเป็นค่าแบบ double
- บรรทัด 12 และ 13 ประกาศตัวแปรชนิด char ซึ่งมีขนาดสิบหกบิต เก็บค่าตัวอักษรได้ระหว่าง U+0000 ('\u0000') ถึง U+FFFF ('\uffff') และมีค่าโดยปริยายเป็น ‘\0’ บรรทัด 14 และ 15 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ B และ x ตามลำดับ โปรดสังเกตบรรทัด 12 คือการกำหนดค่าโดยอ้างรหัส Unicode ส่วนบรรทัด 13 คือการกำหนดค่าด้วยการใส่ตัวอักษรโดยตรง
- บรรทัด 16 ประกาศตัวแปรชนิด decimal ซึ่งมีขนาดร้อยยี่สิบแปดบิต เก็บค่าตัวเลขทศนิยมได้ระหว่าง –7.9 × 10^−28 ถึง 7.9 × 10^28 มีความละเอียดของทศนิยมยี่สิบแปดหลัก และมีค่าโดยปริยายเป็น 0.0M บรรทัด 17 คือคำสั่งแสดงผลัพธ์ที่คอนโซล ผลลัพธ์ที่ได้เมื่อรันโปรแกรมคือ 53005.25 โปรดสังเกตการใส่ตัวอักษร M ไว้หลังตัวเลขที่กำหนดค่าในบรรทัดที่ 16 ซึ่งทำหน้าที่บอกให้คอมไพเลอร์รู้ว่าเป็นค่าแบบ decimal
คุณสมบัติของอินเดกซ์เซอร์ (Indexer)
- เป็นกลไกที่ช่วยให้เราอ้างถึงกลุ่มข้อมูลในออพเจ็กต์โดยใช้ดรรชนีคล้ายอาร์เรย์
- การนิยามอินเดกซ์เซอร์เราจะใช้คำเฉพาะ this
- มีตัวเก็ตเตอร์และตัวเซตเตอร์แบบเดียวกับพรอพเพอร์ตี
- เราสามารถเรียกหาค่าที่ส่งมายังเซตเตอร์ได้โดยผ่านคำเฉพาะ value
- กำหนดดรรชนีได้ตามใจเรา ไม่ต้องเป็นเลขจำนวนเต็มก็ได้
- เราสามารถโอเวอร์โหลดอินเดกซ์เซอร์ได้
- มีพารามิเตอร์ได้มากกว่าหนึ่ง เช่น มีพารามิเตอร์สองตัวเพื่ออ้างถึงอาร์เรย์สองมิติ
ในโค้ดตัวอย่างแสดงวิธีนิยามและใช้งานอินเดกซ์เซอร์แบบธรรมดา บรรทัด 5 ถึง 16 คือนิยามคลาส SampleCollection ซึ่งเป็นคลาสที่เราจะใส่นิยามอินเดกซ์เซอร์ บรรทัด 8 ประกาศตัวแปรอาร์เรย์ที่มีดาต้าไทป์เป็นเจนเนอริก นี่เทียบได้กับการประกาศตัวแปรแบบ “แบกกิงฟิลด์” (backing field) ที่ใช้งานร่วมกับพรอพเพอร์ตี เพราะเราจจะใช้อินเดกซ์เซอร์รับส่งข้อมูลกับมัน บรรทัด 11-15 คือนิยามของอินเดกซ์เซอร์ จะเห็นว่าคล้ายนิยามพรอพเพอร์ตี ซึ่งมีข้อควรสังเกตสามประการคือ
ข้อสังเกตุของ Indexer
- เอกเซสโมดิไฟเออร์ต้องเป็นพับลิกเช่นเดียวกับพอร์พเพอร์ตี
- ตำแหน่งที่ควรจะเป็นชื่อของอินเดกซ์เซอร์ให้ใช้คำเฉพาะ this
- หลังชื่อตามด้วยพารามิเตอร์ที่มีวงเล็บเหลี่ยมแทนที่จะเป็นวงเล็บธรรมดาอย่างในนิยามฟังก์ชัน
- บรรทัดที่ 13 คือเกตเตอร์ทำหน้าที่นำข้อมูลจากตัวแปร arr ตามตำแหน่งที่ระบุโดยดรรชนี ส่งไปยังโค้ดที่เรียกหาอินเดกซ์เซอร์
- บรรทัดที่ 14 คือเซตเตอร์ทำหน้าที่นำข้อมูลจากโค้ดภายนอกไปใส่ในตัวแปร arr ตามตำแหน่งที่ระบุโดยดรรชนี
- โค้ดบรรทัดที่ 18 ถึง 26 คือนิยามคลาส Program ซึ่งมีเมธอด Main อันมีโค้ดที่เราจะใช้เพื่อทดสอบการทำงานของอินเดกซ์เซอร์ โค้ดบรรทัด 22 สร้างออพเจ็กต์ชื่อ MySc จากคลาส SampleCollection บรรทัด 23 คือการส่งค่าไปยังออพเจ็กต์โดยใช้อินเดกซ์เซอร์ ข้อความ Hello, World จะไปที่บรรทัด 14 และกลายเป็นค่าของ value ซี่งจะถูกนำไปใส่ในอาร์เรย์ arr ตำแหน่งที่ศูนย์ โปรดสังเกตว่าโค้ดบรรทัดที่ 23 มีหน้าตาเหมือนการกำหนดค่าให้แก่สตริงอาร์เรย์ไม่มีผิดเพี้ยน สุดท้ายโค้ดบรรทัด 24 สาทิตการอ่านค่าจากออพเจ็กต์โดยใช้อินเดกซ์เซอร์ซึ่งก็มีหน้าตาเหมือนการอ่านค่าจากอาร์เรย์เช่นเดียวกัน
บ่อยนักที่เราต้องการอินเดกซ์เซอร์แบบง่าย ๆ ที่ไม่มีตรรกะใด ๆ อยู่ภายในเกตเตอร์และเซตเตอร์เลย การที่ต้องเขียนเกตเตอร์และเซตเตอร์อย่างเต็มยศจะยืดเยื้อเกินกว่าเหตุ โดยเฉพาะอย่างยิ่งเมื่อมีอินเดกซ์เซอร์อย่างนี้จำนวนมาก เพื่ออำนวยความสะดวกและลดภาระของนักพัฒนาฯ ผู้สร้างภาษาซีชาร์ปจึงปรับปรุง (เริ่มจากเวอร์ชั่นหกเป็นต้นมา) ให้นักเขียนโค้ดสามารถใช้ “เอกซ์เพรสชันบอร์ดี” (Expression body) ร่วมกับอินเดกซ์เซอร์ได้ด้วย ซึ่งมีผลทำให้นิยามของอินเดกซ์เซอร์กะทัดรัดมากขึ้น คือเหลือเพียงบรรทัดเดียว
ในโค้ดตัวอย่างแสดงวิธีนิยามและใช้งานอินเดกซ์เซอร์แบบใช้เอกซ์เพรสชันบอร์ดี บรรทัด 4 ถึง 19 คือนิยามคลาส SampleCollection ซึ่งเป็นคลาสที่เราจะใส่นิยามอินเดกซ์เซอร์แบบใช้เอกซ์เพรสชันบอร์ดี บรรทัด 7 ประกาศตัวแปรอาร์เรย์ที่มีดาต้าไทป์เป็นเจนเนอริก นี่เทียบได้กับการประกาศตัวแปรแบบแบกกิงฟิลด์ (backing field) ที่ใช้งานร่วมกับพรอพเพอร์ตี เพราะเราจจะใช้อินเดกซ์เซอร์รับส่งข้อมูลกับมัน บรรทัด 11 คือนิยามของอินเดกซ์เซอร์ โปรดสังเกตตัวกระทำ => ซี่งทำให้บรรทัดคำสั่งนี้มีภาวะเป็นเอกซ์เพรสชันบอร์ดี
สิ่งที่น่าสังเกตอีกอย่างในตัวอย่างโค้ดนี้คือนิยามอินเดกซ์เซอร์แบบใช้เอกซ์เพรสชันบอร์ดีนี้ ไม่มีโค้ดส่วนเกตเตอร์ ทำให้มันอยู่ในสภาพอ่านได้เท่านั้น ซึ่งจะมีประโยชน์เมื่อเราไม่ต้องการให้โค้ดนอกมาเปลี่ยนแปลงภาวะของออพเจ็กต์ได้โดยตรง ซึ่งในตัวอย่างนี้โค้ดนอกจะเปลี่ยนค่าของออพเจ็กต์ได้โดยอ้อมผ่านเมธอด Add() (ที่นิยามไว้ในคลาส SampleCollection บรรทัดที่ 13 ถึง) 18 เท่านั้น
ในซีชาร์ปเวอร์ชันเจ็ดเป็นต้นมาได้รับการปรับปรุงให้อินเดกซ์เซอร์แบบใช้เอกซ์เพรสชันบอร์ดีมีเกตเตอร์และเซตเตอร์ได้ด้วย โค้ดบรรทัด 10 ถึง 14 คือนิยามอินเดกซ์เซอร์แบบที่ว่านี้ โปรดสังเกตเครื่องหมาย => ในบรรทัด 12 และ 13 ที่ใช้คู่กันกับคำเฉพาะ get และ set การเรียกใช้งานจะกลับไปเหมือนกับอินเดกซ์เซอร์แบบเต็มยศอีกครั้ง แต่นิยามอินเดกซ์เซอร์แบบนี้ดีกว่าแบบดั้งเดิมเพราะโค้ดไม่รกรุงรัง
อย่างที่เรียนให้ทราบไปแล้วว่า เกตเตอร์ของอินเดกซ์เซอร์ไม่จำเป็นต้องใช้ดรรชนีเป็นตัวเลขจำนวนเต็มก็ได้ ในโค้ดตัวอย่างนี้แสดงวิธีนิยามละใช้งานอินเดกซ์เซอร์ที่ใช้สตริงก์เป็นดรรชนี โจทย์คือต้องการทำออพเจ็กต์ที่ให้ค่าตัวเลขของวันในสัปดาห์ เช่น เมื่อโค้ดนอกส่งชื่อวันไปให้ออพเจ็กต์ เช่น Sun ออพเจ็กต์จะให้ค่าเป็นศูนย์ เมื่อโค้ดนอกส่ง Mon ออพเจ็กต์จะให้ค่าเป็นหนึ่ง วิธีทำคือเราจะนิยามเมธอดสำหรับค้นหาตัวเลขของวันไว้ภายในออพเจ็กต์