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

ข้อดีของภาษา C# เมื่อเทียบกับภาษาอื่น ๆ ตอนที่ 3
เกตเตอร์เซตเตอร์ง่ายเร็วในภาษาซีพลัสพลัสเราจะต้องนิยามฟังก์ชันสำหรับการรับ (get) และการส่ง (set) ข้อมูลเอง
ซึ่งกินเวลาและแรงงานมาก แต่ในภาษาซีชาร์พเราสามารถทำได้ด้วยการคลิกเมาส์เพียงไม่กี่ครั้ง
การเกตและเซต (get/set) คือการยอมให้ออพเจ็กต์ผู้เรียกใช้งาน (หรือ bar ในโค้ดตัวอย่าง) สามารถเข้าถึงตัวเก็บข้อมูลที่อยู่ภายในออพเจ็กต์ที่ถูกใช้งาน (ในโค้ดตัวอย่างคือ foo) ได้
ซึ่งเป็นหลักการเอนแคปซูเลชัน (encapsulation) ในการเขียนโปรแกรมแนววัตถุวิธี (Object Oriented Programming)
การเกตและการเซตหากออกแบบอย่างไม่รอบคอบก็อาจทำให้เสียหลักการเอนแคปซูเลชันได้เหมือนกัน
ตัวอย่างโค้ดเพื่อนิยามฟังก์ชันสำหรับการเกตและการเซตในภาษาซีพลัสพลัสเป็นดังนี้
ในตัวอย่างโค้ดภาษาซีพลัสพลัสมีสองคลาสคือ foo (บรรทัดที่ 6 ถึง 13) และ bar (บรรทัดที่ 15 ถึง 23)
คลาส foo คือคลาสที่ bar จะนำไปสร้างออพเจ็กต์ ในคลาสนี้มีโค้ดฟังก์ชันเกตเตอร์ (getter) และเซตเตอร์ (setter)
ส่วนคลาส bar คือคลาสที่มีโค้ดแสดงวิธีการนำคลาส foo ไปสร้างออพเจ็กต์ และเรียกใช้ฟังก์ชันเกตเตอร์และเซตเตอร์ของ foo
โค้ดบรรทัดที่ 9 คือตัวแปร myVar ซึ่งทำหน้าที่เก็บสถานะหรือข้อมูลของออพเจ็กต์
โปรดสังเกตว่ามันมีแอกเซสโมดิไฟเออร์เป็นแบบไพรเวท เพื่อป้องกันไม่ให้โค้ดภายนอก (คลาส bar) เข้าถึงได้โดยตรง
อันเป็นการออกแบบตามหลักการเอนแคปซูเลชันในวิธีเขียนโปรแกรมแบบ OOP ที่ไม่ต้องการเผยกลไกภายในของออพเจ็กต์
บรรทัดที่ 11 เป็นโค้ดเกตเตอร์แบบสั้นที่สุด คือนิยามฟังก์ชัน getMyVar() ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถอ่านค่าของตัวแปร myVar ได้
โปรดสังเกตว่าฟังก์ชันนี้จะต้องมีค่าส่งกลับเป็นชนิดข้อมูลตรงกันกับตัวแปร myVar (คือ int)
และเป็นฟังก์ชันที่ไม่ต้องมีพารามิเตอร์ โค้ดภายในตัวฟังก์ชันมีเพียงคำสั่ง return
ซึ่งจะส่งค่าในตัวแปร myVar กลับไปให้แก่โค้ดที่เรียกใช้ฟังก์ชันนี้
โค้ดบรรทัดที่ 12 เป็นเซตเตอร์แบบสั้นที่สุด คือนิยามฟังก์ชัน setMyVar() ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถเปลี่ยนแปลงค่าของตัวแปร myVar ได้
โปรดสังเกตว่าฟังก์ชันนี้มีค่าส่งกลับเป็น void เพราะไม่จำเป็นต้องส่งค่าอะไรกลับไปให้ผู้เรียก
และเป็นฟังก์ชันที่ “ต้อง” มีพารามิเตอร์เป็นชนิดข้อมูลตรงกันกับตัวแปร myVar (คือ int)
โค้ดภายในตัวฟังก์ชันมีเพียงคำสั่งนำข้อมูลที่รับมาเป็นพารามิเตอร์ไปกำหนดค่าให้กับตัวแปร myVar
ต่อไปมาดูโค้ดของคลาส bar ซึ่งเป็นโค้ดแบบสั้นที่สุดเพื่อสาธิตการเรียกใช้เกตเตอร์และเซตเตอร์
โค้ดบรรทัด 19 สร้างออพเจ็กต์จากคลาส foo โดยประกาศตัวแปร ob เพื่อใช้อ้างถึงออพเจ็กต์นี้
โค้ดบรรทัด 20 คือการเรียกใช้เกตเตอร์โดยเรียกฟังก์ชัน getMyVar() เพื่ออ่านค่าจากออพเจ็กต์มาใส่ในตัวแปร i
ดังนั้นเมื่อโค้ดบรรทัดนี้ทำงานจบลง ตัวแปร i จะมีค่าเท่ากับตัวแปร myVar ของออพเจ็กต์ ob
บรรทัด 21 คือการเรียกใช้เซตเตอร์โดยเรียกฟังก์ชัน setMyVar() โดยกำหนดค่า 12 ให้เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานจบลงตัวแปร myVar ของออพเจ็กต์ ob จะมีค่าเป็น 12
ในโค้ดตัวอย่างเกตเซตนี้ไม่ได้แสดงประโยชน์ที่ชัดเจนของการใช้เกตเซตเพื่อส่งเสริมหลักการเอนแคปซูเลชันเพราะเป็นโค้ดอย่างสั้นที่สุด
เพื่อการอธิบายเกตเซตเท่านั้น จึงดูเหมือนว่า bar สามารถอ่านและเปลี่ยนแปลงค่าของตัวแปร myVar ในออพเจ็กต์ ob ได้ไม่ต่างจากการเข้าถึงตัวแปรแบบพับลิกโดยตรงนัก
แต่ในการใช้งานจริงเราจะใส่โค้ดคัดกรองหรือเงื่อนไขไว้ในฟังก์ชัน setMyVar()
ยกตัวอย่างเช่น เราอาจใส่โค้ดเพื่อป้องกันไม่ให้ bar กำหนดค่าของตัวแปร myVar ต่ำกว่าหรือสูงกว่าย่านที่กำหนดเป็นต้น
ตัวอย่างโค้ดเกตเตอร์และเซตเตอร์ในภาษาซีชาร์พ
คลาส foo คือคลาสที่ bar จะนำไปสร้างออพเจ็กต์ ในคลาสนี้มีโค้ดฟังก์ชันเกตเตอร์ (getter) และเซตเตอร์ (setter)
ส่วนคลาส bar คือคลาสที่มีโค้ดแสดงวิธีการนำคลาส foo ไปสร้างออพเจ็กต์ และเรียกใช้ฟังก์ชันเกตเตอร์และเซตเตอร์ของ foo
โค้ดบรรทัดที่ 9 คือตัวแปร myVar ซึ่งทำหน้าที่เก็บสถานะหรือข้อมูลของออพเจ็กต์
โปรดสังเกตว่ามันมีแอกเซสโมดิไฟเออร์เป็นแบบไพรเวท เพื่อป้องกันไม่ให้โค้ดภายนอก (คลาส bar) เข้าถึงได้โดยตรง
อันเป็นการออกแบบตามหลักการเอนแคปซูเลชันในวิธีเขียนโปรแกรมแบบ OOP ที่ไม่ต้องการเผยกลไกภายในของออพเจ็กต์
บรรทัดที่ 11 เป็นโค้ดเกตเตอร์แบบสั้นที่สุด คือนิยามฟังก์ชัน getMyVar() ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถอ่านค่าของตัวแปร myVar ได้
โปรดสังเกตว่าฟังก์ชันนี้จะต้องมีค่าส่งกลับเป็นชนิดข้อมูลตรงกันกับตัวแปร myVar (คือ int)
และเป็นฟังก์ชันที่ไม่ต้องมีพารามิเตอร์ โค้ดภายในตัวฟังก์ชันมีเพียงคำสั่ง return
ซึ่งจะส่งค่าในตัวแปร myVar กลับไปให้แก่โค้ดที่เรียกใช้ฟังก์ชันนี้
โค้ดบรรทัดที่ 12 เป็นเซตเตอร์แบบสั้นที่สุด คือนิยามฟังก์ชัน setMyVar() ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถเปลี่ยนแปลงค่าของตัวแปร myVar ได้
โปรดสังเกตว่าฟังก์ชันนี้มีค่าส่งกลับเป็น void เพราะไม่จำเป็นต้องส่งค่าอะไรกลับไปให้ผู้เรียก
และเป็นฟังก์ชันที่ “ต้อง” มีพารามิเตอร์เป็นชนิดข้อมูลตรงกันกับตัวแปร myVar (คือ int)
โค้ดภายในตัวฟังก์ชันมีเพียงคำสั่งนำข้อมูลที่รับมาเป็นพารามิเตอร์ไปกำหนดค่าให้กับตัวแปร myVar
ต่อไปมาดูโค้ดของคลาส bar ซึ่งเป็นโค้ดแบบสั้นที่สุดเพื่อสาธิตการเรียกใช้เกตเตอร์และเซตเตอร์
โค้ดบรรทัด 19 สร้างออพเจ็กต์จากคลาส foo โดยประกาศตัวแปร ob เพื่อใช้อ้างถึงออพเจ็กต์นี้
โค้ดบรรทัด 20 คือการเรียกใช้เกตเตอร์โดยเรียกฟังก์ชัน getMyVar() เพื่ออ่านค่าจากออพเจ็กต์มาใส่ในตัวแปร i
ดังนั้นเมื่อโค้ดบรรทัดนี้ทำงานจบลง ตัวแปร i จะมีค่าเท่ากับตัวแปร myVar ของออพเจ็กต์ ob
บรรทัด 21 คือการเรียกใช้เซตเตอร์โดยเรียกฟังก์ชัน setMyVar() โดยกำหนดค่า 12 ให้เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานจบลงตัวแปร myVar ของออพเจ็กต์ ob จะมีค่าเป็น 12
ในโค้ดตัวอย่างเกตเซตนี้ไม่ได้แสดงประโยชน์ที่ชัดเจนของการใช้เกตเซตเพื่อส่งเสริมหลักการเอนแคปซูเลชันเพราะเป็นโค้ดอย่างสั้นที่สุด
เพื่อการอธิบายเกตเซตเท่านั้น จึงดูเหมือนว่า bar สามารถอ่านและเปลี่ยนแปลงค่าของตัวแปร myVar ในออพเจ็กต์ ob ได้ไม่ต่างจากการเข้าถึงตัวแปรแบบพับลิกโดยตรงนัก
แต่ในการใช้งานจริงเราจะใส่โค้ดคัดกรองหรือเงื่อนไขไว้ในฟังก์ชัน setMyVar()
ยกตัวอย่างเช่น เราอาจใส่โค้ดเพื่อป้องกันไม่ให้ bar กำหนดค่าของตัวแปร myVar ต่ำกว่าหรือสูงกว่าย่านที่กำหนดเป็นต้น
ตัวอย่างโค้ดเกตเตอร์และเซตเตอร์ในภาษาซีชาร์พ
การทำเกตเตอร์เซตเตอร์ในภาษาซีชาร์พทำได้ง่ายกว่าและเร็วกว่าในภาษาซีพลัสพลัส
เพราะการทำเกตเตอร์เซตเตอร์ในภาษาซีชาร์พไม่ต้องนิยามฟังก์ชันเนื่องจากมีกลไกพิเศษเพื่อการนี้โดยเฉพาะเรียกว่า “พรอพเพอร์ตี” (property)
ภายในพรอพเพอร์ตีมีคีย์เวิร์ด get และ set ที่ช่วยให้การอ่านโค้ดทำได้ง่าย
เพราะเห็นได้อย่างชัดเจนว่าโค้ดส่วนไหนคือเกตเตอร์และโค้ดส่วนไหนคือเซตเตอร์
นอกจากนั้นเรายังสามารถใช้คุณลักษณะพิเศษที่เรียกว่า “เอกเพรสชันบอร์ดี” (Expression body)
ร่วมกับพอร์พเพอร์ตีได้ด้วยช่วยให้โค้ดในพอร์พเพอร์ตีกระชับไม่รกรุงรัง
ในตัวอย่างโค้ดภาษาซีชาร์พมีสองคลาสคือ foo (บรรทัดที่ 3 ถึง 10) และ bar (บรรทัดที่ 13 ถึง 21)
คลาส foo คือคลาสที่ bar จะนำไปสร้างออพเจ็กต์ ในคลาสนี้มีโค้ดพรอพเพอร์ตี
ส่วนคลาส bar คือคลาสที่มีโค้ดแสดงวิธีนำคลาส foo ไปสร้างออพเจ็กต์ และเรียกใช้พอร์พเพอร์ตีของ foo
โค้ดบรรทัดที่ 5 คือตัวแปร myVar ซึ่งทำหน้าที่เก็บสถานะหรือข้อมูลของออพเจ็กต์
โปรดสังเกตว่ามันมีแอกเซสโมดิไฟเออร์เป็นแบบไพรเวท เพื่อป้องกันไม่ให้โค้ดภายนอก (คลาส bar) เข้าถึงได้โดยตรง
อันเป็นการออกแบบตามหลักการเอนแคปซูเลชันในวิธีเขียนโปรแกรมแบบ OOP ในภาษาซีชาร์พ
เราเรียกตัวแปรซึ่งทำหน้าที่นี้ว่า “แบคกิงฟิลด์” (backing field)
ซึ่งหมายถึงตัวแปรไพรเวทที่มีพอร์พเพอร์ตีอยู่คู่กันเพื่อทำหน้าที่เป็นอินเตอร์เฟสกับโค้ดภายนอก
โค้ดบรรทัดที่ 6 คือนิยามพรอพเพอร์ตีแบบสั้นที่สุดชื่อ MyVar
ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถอ่านค่าของตัวแปร myVar ได้
พรอพเพอร์ตีจะต้องมีแอกเซสโมดิไฟเออร์เป็นพับลิก และจะต้องมีชนิดข้อมูลตรงกันกับตัวแปรแบคกิงฟิลด์ซึ่งในกรณีนี้คือ int
โปรดสังเกตว่าชื่อของพรอพเพอร์ตีนิยมตั้งให้ตรงกันกับชื่อของแบคกิงฟิลด์ที่คู่กัน
ยกเว้นแต่ว่าตัวอักษรตัวแรกจะเป็นตัวใหญ่ นั่นคือชื่อตัวแปรแบคกิงฟิลด์เป็นแบบคาเมลเคส (Camel case)
ส่วนชื่อของพรอพเพอร์ตีเป็นแบบปาสคาลเคส (Pascal case)
โค้ดบรรทัดที่ 8 คือส่วนเกตเตอร์ซึ่งใช้คีย์เวิร์ด get และลูกศรอ้วน (fat arrow
คือเครื่องหมายเท่ากับและมากกว่าเขียนติดกันเป็นตัวกระทำในซินเทกซ์ (syntax วากยสัมพันธ์) แบบเอกเพรสชันบอร์ดี
โปรดอย่าสับสนระหว่างเอกเพรสชันบอร์ดีกับ “แอกเพรสชันทรี” (Expresstion tree) เพราะเครื่องหมายเดียวกันนี้ถูกนำมาใช้ในทั้งสองกรณี)
ทางขวามือของลูกศรอ้วนคือแบคกิงฟิลด์ซึ่งจะถูกนำไปเป็นค่าส่งกลับให้แก่พรอพเพอร์ตีนี้
โปรดสังเกตว่าโค้ดส่วนเกตเตอร์ของพอร์เพอร์ตีไม่ต้องมีคำสั่ง return
โค้ดบรรทัดที่ 9 คือส่วนเซตเตอร์ซึ่งใช้คีย์เวิร์ด set และใช้เอกเพรสชันบอร์ดีเช่นเดียวกับเกตเตอร์
คีย์เวิร์ด value ทำหน้าที่เป็นตัวอ้างอิงค่าที่ผู้ใช้ส่งมาให้เซตเตอร์ (ซึ่งในตัวอย่างโค้ดนี้ก็คือตัวเลข 12 ในบรรทัด 19)
โปรดสังเกตคำว่า myVar = value ซึ่งเป็นนิพจน์คำสั่งให้นำค่า 12 ไปเก็บในแบคกิงฟิลด์
ที่ใส่นิพจน์ไว้ตรงนี้ได้เพราะซินเทกซ์ของเอกเพรสชันบอร์ดีกำหนดไว้ว่าให้สิ่งที่อยู่ทางขวามือของลูกศรอ้วนเป็นนิพจน์
การใช้ซินเทกซ์แบบเอกเพรสชันบอร์ดีร่วมกับพรอพเพอร์ตีทำให้ไม่ต้องตั้งโค้ดบล็อกใหม่ (เขียนวงเล็บปีกกาเปิดปิด)
ซึ่งมีข้อดีคือช่วยให้การนิยามพอร์พเพอร์ตีกะทัดรัด ในกรณีที่พอร์พเพอร์ตีเป็นแบบสั้นที่สุด คือไม่มีตรรกะพิเศษเพิ่มเติมใด ๆ เลย
เราอาจยุบรวมบรรทัดที่ 6 ถึง 10 ไว้เป็นโค้ดบรรทัดเดียวก็ยังได้ โดยการทำเช่นนั้นจะไม่ทำให้โค้ดอ่านยากขึ้นแต่อย่างใด
และหากท่านไม่อยากเขียนพอร์เพอร์ตีด้วยตัวเอง โปรแกรมวิสชวลสตูดิโอ ก็สามารถใส่โค้ดพรอพเพอร์ตีให้ท่านได้โดยอัตโนมัติ
และจะเป็นแบบสั้นที่สุดเหมือนในตัวอย่างนี้ แต่จะจับรวมทั้งหมดไว้ในบรรทัดเดียวกัน
ต่อไปมาดูโค้ดส่วนที่เรียกใช้งานพอร์พเพอร์ตีซึ่งไม่แตกต่างจากโค้ดการเรียกใช้เกตเตอร์เซตเตอร์ในภาษาซีพลัสพลัสมากนัก
โค้ดบรรทัด 17 สร้างออพเจ็กต์จากคลาส foo โดยประกาศตัวแปร ob เพื่อใช้อ้างถึงออพเจ็กต์นี้
โค้ดบรรทัด 18 คือการเรียกใช้เกตเตอร์ด้วยการอ้างถึงพอร์เพอร์ตี MyVar เพื่ออ่านค่าจากออพเจ็กต์มาใส่ในตัวแปร i
ดังนั้นเมื่อโค้ดบรรทัดนี้ทำงานจบลง ตัวแปร i จะมีค่าเท่ากับตัวแปร myVar ของออพเจ็กต์ ob บรรทัด 21
คือการเรียกใช้เซตเตอร์โดยเรียกพอร์เพอร์ตี MyVar กำหนดค่า 12 ให้เป็นเอกเพรสชัน
เมื่อโค้ดบรรทัดนี้ทำงานจบลงตัวแปร myVar ของออพเจ็กต์ ob จะมีค่าเป็น 12
โปรดสังเกตว่าการเรียกใช้พอร์เพอร์ตีในภาษาซีชาร์พ ต่างจากการเรียกใช้เกตเตอร์เซตเตอร์ในภาษาซีพลัสพลัส
เพียงแค่เราไม่ต้องใส่วงเล็บหลังชื่อพอร์พเพอร์ตีในบรรทัดที่ 18 และการเซตค่าของพอร์พเพอร์ตีในบรรทัดที่ 19
เราไม่ต้องใส่ค่าตัวเลขในวงเล็บ สาเหตุที่เป็นเช่นนั้นเพราะพอร์พเพอร์ตีไม่ใช่ฟังก์ชัน (หรือที่ในภาษาซีชาร์พเรียกว่าเมธอด)
ในโค้ดตัวอย่างภาษาซีพลัสพลัสและภาษาซีชาร์พที่ยกมานี้ท่านอาจเห็นว่าไม่ต่างกันมากนัก
ที่เป็นเช่นนั้นเพราะเป็นโค้ดตัวอย่างแบบสั้นที่สุด แต่ในการใช้งานจริงเกตเตอร์เซตเตอร์มักจะยาวและมีจำนวนมากกว่านี้
การเขียนเกตเตอร์เซตเตอร์อย่างในภาษาซีพลัสพลัสจึงเป็นภาระหนักกว่าการเขียนพอร์พเพอร์ตีในภาษาซีชาร์พ
ยิ่งไปกว่านั้นในภาษาซีชาร์พเรายังสามารถให้โปรแกรมวิสชวลสตูดิโอใส่นิยามพอร์พเพอร์ตีให้โดยอัตโนมัติได้ด้วยซึ่งทุ่นเวลาได้มาก
วิธีทำคือให้ประกาศตัวแปรไปรเวทหรือแบคกิงฟิลด์ จากนั้นใช้เมาส์คลิกที่ตัวแปร เลือกเมนู Edit แล้วเลือกหัวข้อ Refactor / Encapsulate Field
เดลลีเกตปลอดภัย
ข้อดีของภาษาซีชาร์พเหนือภาษาซีคือ การทำเดลลีเกตในภาษาซีชาร์พสามารถทำได้โดยไม่ต้องใช้พอยน์เตอร์
การทำเดลลีเกต (delegate) ในภาษาซีจำเป็นจะต้องใช้ฟังก์ชันพอยน์เตอร์ (function pointer) ซึ่งไม่ค่อยปลอดภัยนัก เพราะเราสามารถแคส (cast แปลงชนิดข้อมูล) พอยน์เตอร์ไปเป็นอะไรก็ได้จึงมีความเสี่ยงที่จะผิดพลาดเผลอเรอ ทำให้ฟังก์ชันพอยน์เตอร์ชี้ไปผิดฟังก์ชัน ส่วนภาษาซีชาร์พมีชนิดข้อมูลแบบเดลลีเกต (delegate type) โดยเฉพาะ การทำเดลลีเกตในภาษาซีชาร์พจึงมีภาวะเป็นไทป์เซฟ (type-safe การไม่คลาดเคลื่อนจากชนิดข้อมูลแบบหนึ่งไปเป็นอีกแบบหนึ่ง) ที่เรามั่นใจได้ว่าจะอ้างอิงไปยังเมธอดที่กำหนดอย่างแน่นอน
ตัวอย่างโค้ดภาษาซีแสดงการทำเดลลีเกตด้วยฟังก์ชันพอยน์เตอร์
เพราะการทำเกตเตอร์เซตเตอร์ในภาษาซีชาร์พไม่ต้องนิยามฟังก์ชันเนื่องจากมีกลไกพิเศษเพื่อการนี้โดยเฉพาะเรียกว่า “พรอพเพอร์ตี” (property)
ภายในพรอพเพอร์ตีมีคีย์เวิร์ด get และ set ที่ช่วยให้การอ่านโค้ดทำได้ง่าย
เพราะเห็นได้อย่างชัดเจนว่าโค้ดส่วนไหนคือเกตเตอร์และโค้ดส่วนไหนคือเซตเตอร์
นอกจากนั้นเรายังสามารถใช้คุณลักษณะพิเศษที่เรียกว่า “เอกเพรสชันบอร์ดี” (Expression body)
ร่วมกับพอร์พเพอร์ตีได้ด้วยช่วยให้โค้ดในพอร์พเพอร์ตีกระชับไม่รกรุงรัง
ในตัวอย่างโค้ดภาษาซีชาร์พมีสองคลาสคือ foo (บรรทัดที่ 3 ถึง 10) และ bar (บรรทัดที่ 13 ถึง 21)
คลาส foo คือคลาสที่ bar จะนำไปสร้างออพเจ็กต์ ในคลาสนี้มีโค้ดพรอพเพอร์ตี
ส่วนคลาส bar คือคลาสที่มีโค้ดแสดงวิธีนำคลาส foo ไปสร้างออพเจ็กต์ และเรียกใช้พอร์พเพอร์ตีของ foo
โค้ดบรรทัดที่ 5 คือตัวแปร myVar ซึ่งทำหน้าที่เก็บสถานะหรือข้อมูลของออพเจ็กต์
โปรดสังเกตว่ามันมีแอกเซสโมดิไฟเออร์เป็นแบบไพรเวท เพื่อป้องกันไม่ให้โค้ดภายนอก (คลาส bar) เข้าถึงได้โดยตรง
อันเป็นการออกแบบตามหลักการเอนแคปซูเลชันในวิธีเขียนโปรแกรมแบบ OOP ในภาษาซีชาร์พ
เราเรียกตัวแปรซึ่งทำหน้าที่นี้ว่า “แบคกิงฟิลด์” (backing field)
ซึ่งหมายถึงตัวแปรไพรเวทที่มีพอร์พเพอร์ตีอยู่คู่กันเพื่อทำหน้าที่เป็นอินเตอร์เฟสกับโค้ดภายนอก
โค้ดบรรทัดที่ 6 คือนิยามพรอพเพอร์ตีแบบสั้นที่สุดชื่อ MyVar
ซึ่งทำหน้าที่ให้โค้ดภายนอกสามารถอ่านค่าของตัวแปร myVar ได้
พรอพเพอร์ตีจะต้องมีแอกเซสโมดิไฟเออร์เป็นพับลิก และจะต้องมีชนิดข้อมูลตรงกันกับตัวแปรแบคกิงฟิลด์ซึ่งในกรณีนี้คือ int
โปรดสังเกตว่าชื่อของพรอพเพอร์ตีนิยมตั้งให้ตรงกันกับชื่อของแบคกิงฟิลด์ที่คู่กัน
ยกเว้นแต่ว่าตัวอักษรตัวแรกจะเป็นตัวใหญ่ นั่นคือชื่อตัวแปรแบคกิงฟิลด์เป็นแบบคาเมลเคส (Camel case)
ส่วนชื่อของพรอพเพอร์ตีเป็นแบบปาสคาลเคส (Pascal case)
โค้ดบรรทัดที่ 8 คือส่วนเกตเตอร์ซึ่งใช้คีย์เวิร์ด get และลูกศรอ้วน (fat arrow
คือเครื่องหมายเท่ากับและมากกว่าเขียนติดกันเป็นตัวกระทำในซินเทกซ์ (syntax วากยสัมพันธ์) แบบเอกเพรสชันบอร์ดี
โปรดอย่าสับสนระหว่างเอกเพรสชันบอร์ดีกับ “แอกเพรสชันทรี” (Expresstion tree) เพราะเครื่องหมายเดียวกันนี้ถูกนำมาใช้ในทั้งสองกรณี)
ทางขวามือของลูกศรอ้วนคือแบคกิงฟิลด์ซึ่งจะถูกนำไปเป็นค่าส่งกลับให้แก่พรอพเพอร์ตีนี้
โปรดสังเกตว่าโค้ดส่วนเกตเตอร์ของพอร์เพอร์ตีไม่ต้องมีคำสั่ง return
โค้ดบรรทัดที่ 9 คือส่วนเซตเตอร์ซึ่งใช้คีย์เวิร์ด set และใช้เอกเพรสชันบอร์ดีเช่นเดียวกับเกตเตอร์
คีย์เวิร์ด value ทำหน้าที่เป็นตัวอ้างอิงค่าที่ผู้ใช้ส่งมาให้เซตเตอร์ (ซึ่งในตัวอย่างโค้ดนี้ก็คือตัวเลข 12 ในบรรทัด 19)
โปรดสังเกตคำว่า myVar = value ซึ่งเป็นนิพจน์คำสั่งให้นำค่า 12 ไปเก็บในแบคกิงฟิลด์
ที่ใส่นิพจน์ไว้ตรงนี้ได้เพราะซินเทกซ์ของเอกเพรสชันบอร์ดีกำหนดไว้ว่าให้สิ่งที่อยู่ทางขวามือของลูกศรอ้วนเป็นนิพจน์
การใช้ซินเทกซ์แบบเอกเพรสชันบอร์ดีร่วมกับพรอพเพอร์ตีทำให้ไม่ต้องตั้งโค้ดบล็อกใหม่ (เขียนวงเล็บปีกกาเปิดปิด)
ซึ่งมีข้อดีคือช่วยให้การนิยามพอร์พเพอร์ตีกะทัดรัด ในกรณีที่พอร์พเพอร์ตีเป็นแบบสั้นที่สุด คือไม่มีตรรกะพิเศษเพิ่มเติมใด ๆ เลย
เราอาจยุบรวมบรรทัดที่ 6 ถึง 10 ไว้เป็นโค้ดบรรทัดเดียวก็ยังได้ โดยการทำเช่นนั้นจะไม่ทำให้โค้ดอ่านยากขึ้นแต่อย่างใด
และหากท่านไม่อยากเขียนพอร์เพอร์ตีด้วยตัวเอง โปรแกรมวิสชวลสตูดิโอ ก็สามารถใส่โค้ดพรอพเพอร์ตีให้ท่านได้โดยอัตโนมัติ
และจะเป็นแบบสั้นที่สุดเหมือนในตัวอย่างนี้ แต่จะจับรวมทั้งหมดไว้ในบรรทัดเดียวกัน
ต่อไปมาดูโค้ดส่วนที่เรียกใช้งานพอร์พเพอร์ตีซึ่งไม่แตกต่างจากโค้ดการเรียกใช้เกตเตอร์เซตเตอร์ในภาษาซีพลัสพลัสมากนัก
โค้ดบรรทัด 17 สร้างออพเจ็กต์จากคลาส foo โดยประกาศตัวแปร ob เพื่อใช้อ้างถึงออพเจ็กต์นี้
โค้ดบรรทัด 18 คือการเรียกใช้เกตเตอร์ด้วยการอ้างถึงพอร์เพอร์ตี MyVar เพื่ออ่านค่าจากออพเจ็กต์มาใส่ในตัวแปร i
ดังนั้นเมื่อโค้ดบรรทัดนี้ทำงานจบลง ตัวแปร i จะมีค่าเท่ากับตัวแปร myVar ของออพเจ็กต์ ob บรรทัด 21
คือการเรียกใช้เซตเตอร์โดยเรียกพอร์เพอร์ตี MyVar กำหนดค่า 12 ให้เป็นเอกเพรสชัน
เมื่อโค้ดบรรทัดนี้ทำงานจบลงตัวแปร myVar ของออพเจ็กต์ ob จะมีค่าเป็น 12
โปรดสังเกตว่าการเรียกใช้พอร์เพอร์ตีในภาษาซีชาร์พ ต่างจากการเรียกใช้เกตเตอร์เซตเตอร์ในภาษาซีพลัสพลัส
เพียงแค่เราไม่ต้องใส่วงเล็บหลังชื่อพอร์พเพอร์ตีในบรรทัดที่ 18 และการเซตค่าของพอร์พเพอร์ตีในบรรทัดที่ 19
เราไม่ต้องใส่ค่าตัวเลขในวงเล็บ สาเหตุที่เป็นเช่นนั้นเพราะพอร์พเพอร์ตีไม่ใช่ฟังก์ชัน (หรือที่ในภาษาซีชาร์พเรียกว่าเมธอด)
ในโค้ดตัวอย่างภาษาซีพลัสพลัสและภาษาซีชาร์พที่ยกมานี้ท่านอาจเห็นว่าไม่ต่างกันมากนัก
ที่เป็นเช่นนั้นเพราะเป็นโค้ดตัวอย่างแบบสั้นที่สุด แต่ในการใช้งานจริงเกตเตอร์เซตเตอร์มักจะยาวและมีจำนวนมากกว่านี้
การเขียนเกตเตอร์เซตเตอร์อย่างในภาษาซีพลัสพลัสจึงเป็นภาระหนักกว่าการเขียนพอร์พเพอร์ตีในภาษาซีชาร์พ
ยิ่งไปกว่านั้นในภาษาซีชาร์พเรายังสามารถให้โปรแกรมวิสชวลสตูดิโอใส่นิยามพอร์พเพอร์ตีให้โดยอัตโนมัติได้ด้วยซึ่งทุ่นเวลาได้มาก
วิธีทำคือให้ประกาศตัวแปรไปรเวทหรือแบคกิงฟิลด์ จากนั้นใช้เมาส์คลิกที่ตัวแปร เลือกเมนู Edit แล้วเลือกหัวข้อ Refactor / Encapsulate Field
เดลลีเกตปลอดภัย
ข้อดีของภาษาซีชาร์พเหนือภาษาซีคือ การทำเดลลีเกตในภาษาซีชาร์พสามารถทำได้โดยไม่ต้องใช้พอยน์เตอร์
การทำเดลลีเกต (delegate) ในภาษาซีจำเป็นจะต้องใช้ฟังก์ชันพอยน์เตอร์ (function pointer) ซึ่งไม่ค่อยปลอดภัยนัก เพราะเราสามารถแคส (cast แปลงชนิดข้อมูล) พอยน์เตอร์ไปเป็นอะไรก็ได้จึงมีความเสี่ยงที่จะผิดพลาดเผลอเรอ ทำให้ฟังก์ชันพอยน์เตอร์ชี้ไปผิดฟังก์ชัน ส่วนภาษาซีชาร์พมีชนิดข้อมูลแบบเดลลีเกต (delegate type) โดยเฉพาะ การทำเดลลีเกตในภาษาซีชาร์พจึงมีภาวะเป็นไทป์เซฟ (type-safe การไม่คลาดเคลื่อนจากชนิดข้อมูลแบบหนึ่งไปเป็นอีกแบบหนึ่ง) ที่เรามั่นใจได้ว่าจะอ้างอิงไปยังเมธอดที่กำหนดอย่างแน่นอน
ตัวอย่างโค้ดภาษาซีแสดงการทำเดลลีเกตด้วยฟังก์ชันพอยน์เตอร์
ในตัวอย่างโค้ดภาษาซีแสดงการทำเดลลีเกตด้วยฟังก์ชันพอยน์เตอร์บรรทัดที่ 3 คือการประกาศฟังก์ชันพอยน์เตอร์ชื่อ Del
การประกาศโดยวิธีนี้จะมีผลให้เราสามารถใช้ Del อ้างอิงถึงฟังก์ชันอะไรก็ได้ที่มีซิกเนเจอร์ (Signature ลักษณะของค่าส่งกลับและรายการอาร์กิวเมนต์) ตรงกับที่ระบุไว้นี้
กล่าวคือมีค่าส่งกลับเป็นตัวเลขจำนวนเต็ม และมีอาร์กิวเมนต์สองตัว ทั้งสองตัวมีชนิดข้อมูลแบบเลขจำนวนเต็ม
บรรทัดที่ 5-8 คือนิยามฟังก์ชัน show ซึ่งเราจะใช้เพื่อแสดงการทำงานของเดลลีเกต
ฟังก์ชันนี้รับพารามิเตอร์หนึ่งตัวเป็นชนิดข้อมูลแบบจำนวนเต็ม การทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่เอาต์พุตมาตรฐาน ์หนึ่งตัว
และการทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่คอนโซล (standard output หรือ stdout)
บรรทัดที่ 10-13 คือนิยามฟังก์ชัน add ซึ่งเป็นฟังก์ชันที่เราจะใช้ฟังก์ชันพอยน์เตอร์ชี้ไป
การทำงานของฟังก์ชันนี้เพียงแค่นำพารามิเตอร์สองตัวมาบวกกันและส่งผลลัพธ์กลับไปยังผู้เรียก
โปรดสังเกตว่าฟังก์ชันนี้มีซิกเนเจอร์ตรงกันกับฟังก์ชันพอยน์เตอร์
บรรทัดที่ 15-18 คือนิยามฟังก์ชัน delete ซึ่งเหมือนกับฟังก์ชัน add แต่การทำงานจะให้ค่าลบของพารามิเตอร์ทั้งสอง
บรรทัดที่ 20-27 คือนิยามฟังก์ชัน main ที่มีโค้ดแสดงวิธีใช้ฟังก์ชันพอยน์เตอร์เพื่อการทำเดลลีเกต
บรรทัด 22 กำหนดให้ฟังก์ชันพอยน์เตอร์ชี้ไปยังฟังก์ชัน add
บรรทัดที่ 23 แสดงการเรียกให้ฟังก์ชันพอยน์เตอร์ทำงานโดยเรียกใช้ฟังก์ชัน show แล้วกำหนดให้ฟังก์ชันพอยน์เตอร์เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานฟังก์ชัน add จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่ stdout
บรรทัด 24 ย้ายให้ฟังก์ชันพอยน์เตอร์ชี้ไปยังฟังก์ชัน delete
บรรทัดที่ 25 แสดงการเรียกให้ฟังก์ชันพอยน์เตอร์ทำงานโดยเรียกใช้ฟังก์ชัน show แล้วกำหนดให้ฟังก์ชันพอยน์เตอร์เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานฟังก์ชัน delete จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่ stdout เช่นกัน
ในตัวอย่างนี้ท่านจะเห็นว่าโค้ดบรรทัดที่ 24 และ 25 มีหน้าตาเหมือนกันทุกอย่างแต่การทำงานกลับให้ผลลัพธ์ที่ต่างกัน
เพราะฟังก์ชันพอย์นเตอร์ชี้ไปยังฟังก์ชันคนละตัวกัน
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำเดลลีเกตด้วยดาต้าไทป์ delegate
การประกาศโดยวิธีนี้จะมีผลให้เราสามารถใช้ Del อ้างอิงถึงฟังก์ชันอะไรก็ได้ที่มีซิกเนเจอร์ (Signature ลักษณะของค่าส่งกลับและรายการอาร์กิวเมนต์) ตรงกับที่ระบุไว้นี้
กล่าวคือมีค่าส่งกลับเป็นตัวเลขจำนวนเต็ม และมีอาร์กิวเมนต์สองตัว ทั้งสองตัวมีชนิดข้อมูลแบบเลขจำนวนเต็ม
บรรทัดที่ 5-8 คือนิยามฟังก์ชัน show ซึ่งเราจะใช้เพื่อแสดงการทำงานของเดลลีเกต
ฟังก์ชันนี้รับพารามิเตอร์หนึ่งตัวเป็นชนิดข้อมูลแบบจำนวนเต็ม การทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่เอาต์พุตมาตรฐาน ์หนึ่งตัว
และการทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่คอนโซล (standard output หรือ stdout)
บรรทัดที่ 10-13 คือนิยามฟังก์ชัน add ซึ่งเป็นฟังก์ชันที่เราจะใช้ฟังก์ชันพอยน์เตอร์ชี้ไป
การทำงานของฟังก์ชันนี้เพียงแค่นำพารามิเตอร์สองตัวมาบวกกันและส่งผลลัพธ์กลับไปยังผู้เรียก
โปรดสังเกตว่าฟังก์ชันนี้มีซิกเนเจอร์ตรงกันกับฟังก์ชันพอยน์เตอร์
บรรทัดที่ 15-18 คือนิยามฟังก์ชัน delete ซึ่งเหมือนกับฟังก์ชัน add แต่การทำงานจะให้ค่าลบของพารามิเตอร์ทั้งสอง
บรรทัดที่ 20-27 คือนิยามฟังก์ชัน main ที่มีโค้ดแสดงวิธีใช้ฟังก์ชันพอยน์เตอร์เพื่อการทำเดลลีเกต
บรรทัด 22 กำหนดให้ฟังก์ชันพอยน์เตอร์ชี้ไปยังฟังก์ชัน add
บรรทัดที่ 23 แสดงการเรียกให้ฟังก์ชันพอยน์เตอร์ทำงานโดยเรียกใช้ฟังก์ชัน show แล้วกำหนดให้ฟังก์ชันพอยน์เตอร์เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานฟังก์ชัน add จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่ stdout
บรรทัด 24 ย้ายให้ฟังก์ชันพอยน์เตอร์ชี้ไปยังฟังก์ชัน delete
บรรทัดที่ 25 แสดงการเรียกให้ฟังก์ชันพอยน์เตอร์ทำงานโดยเรียกใช้ฟังก์ชัน show แล้วกำหนดให้ฟังก์ชันพอยน์เตอร์เป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานฟังก์ชัน delete จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่ stdout เช่นกัน
ในตัวอย่างนี้ท่านจะเห็นว่าโค้ดบรรทัดที่ 24 และ 25 มีหน้าตาเหมือนกันทุกอย่างแต่การทำงานกลับให้ผลลัพธ์ที่ต่างกัน
เพราะฟังก์ชันพอย์นเตอร์ชี้ไปยังฟังก์ชันคนละตัวกัน
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำเดลลีเกตด้วยดาต้าไทป์ delegate
ในตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำเดลลีเกตด้วยดาต้าไทป์ delegate
บรรทัดที่ 12 คือการประกาศดาต้าไทป์แบบเดลลิเกตชื่อ Del (ไม่ใช่การประกาศตัวแปร)
การประกาศโดยเขียนเช่นนี้จะมีผลให้เราสามารถใช้ Del สร้างตัวแปรอ้างอิงถึงเมธอดอะไรก็ได้ที่มีซิกเนเจอร์ตรงกับที่ประกาศไว้นี้
กล่าวคือมีค่าส่งกลับเป็นตัวเลขจำนวนเต็ม และมีอาร์กิวเมนต์สองตัว (คือ a และ b) อาร์กิวเมนต์ทั้งสองตัวมีชนิดข้อมูลแบบเลขจำนวนเต็ม
บรรทัดที่ 14-17 คือนิยามเมธอด Show ใช้เพื่อแสดงการทำงานของเดลลีเกต
เมธอดนี้รับพารามิเตอร์หนึ่งตัวเป็นชนิดข้อมูลแบบจำนวนเต็ม การทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่คอนโซล
บรรทัดที่ 18-21 คือนิยามเมธอด Add ซึ่งเราจะใช้เดลลีเกตชี้มายังเมธอดนี้
การทำงานของเมธอดนี้เพียงแค่นำพารามิเตอร์สองตัวมาบวกกันและส่งผลลัพธ์กลับไปยังผู้เรียก
โปรดสังเกตว่าเมธอดนี้มีซิกเนเจอร์ตรงกันกับเดลลีเกตที่นิยามไว้ที่บรรทัด 12
บรรทัดที่ 22-25 คือนิยามเมธอด Delete ซึ่งเหมือนกับเมธอด Add แต่การทำงานจะให้ค่าลบของพารามิเตอร์ทั้งสอง
บรรทัดที่ 26-32 คือนิยามเมธอด Main ที่มีโค้ดแสดงวิธีใช้งานเดลลีเกต
บรรทัด 28 ประกาศตัวแปรชื่อ myDel ซึ่งมีดาต้าไทป์เป็น Del ซึ่งเป็นเดลลีเกตที่เรานิยามไว้ที่บรรทัด 12 และกำหนดให้ชี้ไปยังเมธอด Add
บรรทัดที่ 29 แสดงการเรียกให้เดลลีเกตทำงานโดยเรียกใช้เมธอด Show แล้วกำหนดให้เดลลีเกตเป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานเมธอด Add จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่คอนโซล
บรรทัด 30 ย้ายให้เดลลีเกตชี้ไปยังเมธอด Delete
บรรทัดที่ 31 แสดงการเรียกให้เดลลีเกตทำงานโดยเรียกใช้เมธอด Show แล้วกำหนดให้เดลลีเกตเป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานเมธอด delete จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่คอนโซลเช่นเดียวกัน
ในโค้ดตัวอย่างสองอันที่ผ่านมาท่านจะเห็นว่าการทำเดลลีเกตในภาษาซีโดยใช้ฟังก์ชันพอยน์เตอร์กับการทำเดลลีเกตในภาษาซีชาร์พ
โดยใช้ดาต้าไทป์ delegate มีโค้ดและวิธีเรียกใช้คล้ายกัน ต่างกันที่เดลลีเกตในภาษาซีชาร์พไม่ต้องใช้พอยน์เตอร์จึงเป็นไทป์เซฟ และมีโค้ดที่อ่านง่ายกว่า
นอกจากนั้นเดลลีเกตในภาษาซีชาร์พยังสามารถทำ “มัลติแคส” (Multicast Delegates การใช้เดลลีเกตตัวเดียวอ้างถึงหลาย ๆ เมธอดพร้อม ๆ กัน) ได้ด้วย
โดยเราสามารถไล่การทำงานของแต่ละเมธอดไปตามลำดับได้เพราะดาต้าไทป์เดลลีเกตมีกลไกวนค่า (iterator) มาให้ในตัวด้วย
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำเดลลีเกตแบบมัลติแคส
บรรทัดที่ 12 คือการประกาศดาต้าไทป์แบบเดลลิเกตชื่อ Del (ไม่ใช่การประกาศตัวแปร)
การประกาศโดยเขียนเช่นนี้จะมีผลให้เราสามารถใช้ Del สร้างตัวแปรอ้างอิงถึงเมธอดอะไรก็ได้ที่มีซิกเนเจอร์ตรงกับที่ประกาศไว้นี้
กล่าวคือมีค่าส่งกลับเป็นตัวเลขจำนวนเต็ม และมีอาร์กิวเมนต์สองตัว (คือ a และ b) อาร์กิวเมนต์ทั้งสองตัวมีชนิดข้อมูลแบบเลขจำนวนเต็ม
บรรทัดที่ 14-17 คือนิยามเมธอด Show ใช้เพื่อแสดงการทำงานของเดลลีเกต
เมธอดนี้รับพารามิเตอร์หนึ่งตัวเป็นชนิดข้อมูลแบบจำนวนเต็ม การทำงานเพียงแค่นำค่าในพารามิเตอร์ออกแสดงที่คอนโซล
บรรทัดที่ 18-21 คือนิยามเมธอด Add ซึ่งเราจะใช้เดลลีเกตชี้มายังเมธอดนี้
การทำงานของเมธอดนี้เพียงแค่นำพารามิเตอร์สองตัวมาบวกกันและส่งผลลัพธ์กลับไปยังผู้เรียก
โปรดสังเกตว่าเมธอดนี้มีซิกเนเจอร์ตรงกันกับเดลลีเกตที่นิยามไว้ที่บรรทัด 12
บรรทัดที่ 22-25 คือนิยามเมธอด Delete ซึ่งเหมือนกับเมธอด Add แต่การทำงานจะให้ค่าลบของพารามิเตอร์ทั้งสอง
บรรทัดที่ 26-32 คือนิยามเมธอด Main ที่มีโค้ดแสดงวิธีใช้งานเดลลีเกต
บรรทัด 28 ประกาศตัวแปรชื่อ myDel ซึ่งมีดาต้าไทป์เป็น Del ซึ่งเป็นเดลลีเกตที่เรานิยามไว้ที่บรรทัด 12 และกำหนดให้ชี้ไปยังเมธอด Add
บรรทัดที่ 29 แสดงการเรียกให้เดลลีเกตทำงานโดยเรียกใช้เมธอด Show แล้วกำหนดให้เดลลีเกตเป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานเมธอด Add จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่คอนโซล
บรรทัด 30 ย้ายให้เดลลีเกตชี้ไปยังเมธอด Delete
บรรทัดที่ 31 แสดงการเรียกให้เดลลีเกตทำงานโดยเรียกใช้เมธอด Show แล้วกำหนดให้เดลลีเกตเป็นอาร์กิวเมนต์
เมื่อโค้ดบรรทัดนี้ทำงานเมธอด delete จะถูกเรียกให้ทำงาน ผลลัพธ์จากการคำนวณจะถูกนำออกแสดงที่คอนโซลเช่นเดียวกัน
ในโค้ดตัวอย่างสองอันที่ผ่านมาท่านจะเห็นว่าการทำเดลลีเกตในภาษาซีโดยใช้ฟังก์ชันพอยน์เตอร์กับการทำเดลลีเกตในภาษาซีชาร์พ
โดยใช้ดาต้าไทป์ delegate มีโค้ดและวิธีเรียกใช้คล้ายกัน ต่างกันที่เดลลีเกตในภาษาซีชาร์พไม่ต้องใช้พอยน์เตอร์จึงเป็นไทป์เซฟ และมีโค้ดที่อ่านง่ายกว่า
นอกจากนั้นเดลลีเกตในภาษาซีชาร์พยังสามารถทำ “มัลติแคส” (Multicast Delegates การใช้เดลลีเกตตัวเดียวอ้างถึงหลาย ๆ เมธอดพร้อม ๆ กัน) ได้ด้วย
โดยเราสามารถไล่การทำงานของแต่ละเมธอดไปตามลำดับได้เพราะดาต้าไทป์เดลลีเกตมีกลไกวนค่า (iterator) มาให้ในตัวด้วย
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำเดลลีเกตแบบมัลติแคส
โค้ดบรรทัดที่ 11 ประกาศเดลลีเกตเพื่อให้ใช้กับเมธอดที่มีค่าส่งกลับเป็นอินทีเจอร์และไม่มีอาร์กิวเมนต์
บรรทัดที่ 14 ประกาศตัวแปรชื่อ myDelegate แล้วกำหนดให้ชี้ไปยังเมธอด One
บรรทัด 15 ผูก myDelegate กับเมธอดเพิ่มอีกหนึ่งเมธอด (คือเมธอด Two) ทำให้ myDelegate ชี้ไปยังเมธอดสองเมธอดพร้อม ๆ กัน
บรรทัด 16 เรียกให้เดลลีเกตทำงานซึ่งจะมีผลให้เมธอด One และ Two ทำงานไล่ไปตามลำดับ
ทำคลาสซ้อนคลาสได้
ข้อได้เปรียบอีกอย่างของภาษาซีชาร์พ คือ เราสามารถประกาศนิยามคลาสไว้ภายในคลาสได้ ขณะที่บางภาษา
(เช่นจาวาสคริปต์ ES6) ทำไม่ได้ เพราะในภาษาซีชาร์พสมาชิกของคลาสนอกจากจะเป็น ตัวแปร เมธอด พรอพเพอร์ตี ฯลฯ ได้แล้ว
คลาสเองก็เป็นสมาชิกของคลาสได้ด้วยเหมือนกัน ประโยชน์ของการทำคลาสซ้อนคลาส
คือ เราสามารถซ่อนโครงสร้างหรือกลไกบางอย่างภายในคลาสไว้จากโลกภายนอก
ยกตัวอย่างเช่น เมื่อเรานิยามลิงค์ลิสต์ เราอาจไม่ต้องการให้โค้ดอื่น ๆ มองเห็นคลาสโหนดด้วยสองสาเหตุ
สาเหตุแรกคือต้องการซ่อนความซับซ้อนเพื่อให้โค้ดภายนอกใช้งานลิสต์ได้โดยไม่รู้ว่ามันทำงานอย่างไร
สองคือป้องกันไม่ให้โค้ดนอกนำคลาสโหนดไปใช้งานโดยตรง
เพื่อให้เราสามารถเปลี่ยนแปลงแก้ไขคลาสโหนดภายหลังได้โดยไม่ส่งผลกระทบกับการทำงานของโค้ดภายนอก
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำคลาสซ้อนคลาส
บรรทัดที่ 14 ประกาศตัวแปรชื่อ myDelegate แล้วกำหนดให้ชี้ไปยังเมธอด One
บรรทัด 15 ผูก myDelegate กับเมธอดเพิ่มอีกหนึ่งเมธอด (คือเมธอด Two) ทำให้ myDelegate ชี้ไปยังเมธอดสองเมธอดพร้อม ๆ กัน
บรรทัด 16 เรียกให้เดลลีเกตทำงานซึ่งจะมีผลให้เมธอด One และ Two ทำงานไล่ไปตามลำดับ
ทำคลาสซ้อนคลาสได้
ข้อได้เปรียบอีกอย่างของภาษาซีชาร์พ คือ เราสามารถประกาศนิยามคลาสไว้ภายในคลาสได้ ขณะที่บางภาษา
(เช่นจาวาสคริปต์ ES6) ทำไม่ได้ เพราะในภาษาซีชาร์พสมาชิกของคลาสนอกจากจะเป็น ตัวแปร เมธอด พรอพเพอร์ตี ฯลฯ ได้แล้ว
คลาสเองก็เป็นสมาชิกของคลาสได้ด้วยเหมือนกัน ประโยชน์ของการทำคลาสซ้อนคลาส
คือ เราสามารถซ่อนโครงสร้างหรือกลไกบางอย่างภายในคลาสไว้จากโลกภายนอก
ยกตัวอย่างเช่น เมื่อเรานิยามลิงค์ลิสต์ เราอาจไม่ต้องการให้โค้ดอื่น ๆ มองเห็นคลาสโหนดด้วยสองสาเหตุ
สาเหตุแรกคือต้องการซ่อนความซับซ้อนเพื่อให้โค้ดภายนอกใช้งานลิสต์ได้โดยไม่รู้ว่ามันทำงานอย่างไร
สองคือป้องกันไม่ให้โค้ดนอกนำคลาสโหนดไปใช้งานโดยตรง
เพื่อให้เราสามารถเปลี่ยนแปลงแก้ไขคลาสโหนดภายหลังได้โดยไม่ส่งผลกระทบกับการทำงานของโค้ดภายนอก
ตัวอย่างโค้ดภาษาซีชาร์พแสดงการทำคลาสซ้อนคลาส
โค้ดตัวอย่างนี้แสดงการนิยามลิงค์ลิสต์เดี่ยว (single linked list) แบบสั้นที่สุดเพื่อสาธิตการใช้งานคลาสซ้อนคลาส (nested class)
โค้ดบรรทัดที่ 4-35 คือนิยามคลาส List ซึ่งมีคลาส Node ซ้อนอยู่ภายใน (บรรทัดที่ 10)
คลาส Node มีสมาชิกแบบฟิลด์อยู่เพียงสองตัวทำให้ดูเหมือนเป็นการใช้งานแบบ struc แต่ไม่จำเป็นต้องเป็นเช่นนั้น
เพราะเราอาจใส่สมาชิกแบบอื่น ๆ เช่นเมธอดและพอร์พเพอร์ตีในคลาส Node ได้เหมือนคลาสทั่วไป
โปรดสังเกตว่าเรากำหนดเอกเซสโมดิไฟเออร์ของคลาส Node ให้เป็นไปรเวทแต่กำหนดให้สมาชิกของมันเป็นพับลิก
บรรทัด 11-12 แสดงการประกาศดาต้าฟิลด์ที่มีไทป์เป็น Node
บรรทัดที่ 14-18 คือเมธอดคอนสตรักเตอร์ (constructor method) ของคลาส List จะเห็นการนำคลาส Node มาสร้างเป็นออพเจ็กต์สองตัว
บรรทัด 19-34 คือเมธอด Insert ทำหน้าที่เพิ่มโหนดใหม่เข้าไปในลิสต์ ในนี้จะเห็นการนำออพเจ็กต์ที่ถูกสร้างจากคลาส Node มาใช้งานสามตัวคือ n, head และ tail
บรรทัด 37-46 คือคลาส Program มีโค้ดที่แสดงการนำคลาส List มาสร้างออพเจ็กต์เพื่อใช้งานในบรรทัดที่ 41
โปรดสังเกตว่าคลาส Program จะมองเห็นคลาส List แต่มองไม่เห็นคลาส Node
บรรทัด 42-44 เรียกเมธอด Insert ของออพเจ็กต์ myList เพื่อเพิ่มโหนดใหม่เข้าไปในลิสต์ได้โดยไม่ต้องอ้างถึงคลาส Node เลย
ในตัวอย่างโค้ดที่ยกมานี้คลาส List มีภาวะเป็นคลาสภายนอก (outer class หรือ containing class)
ส่วนคลาส Node มีภาวะเป็นคลาสภายใน (nested class) ซี่งจะมีสถานะเป็นไปรเวทโดยปริยายเพื่อให้ถูกเรียกใช้จากภายนอกไม่ได้
แต่ท่านสามารถเปลี่ยนแปลงเอกเซสโมดิไฟเออร์ของมันให้เป็น public, protected, internal, protected internal หรือ private protected ก็ได้ตามต้องการ
โค้ดบรรทัดที่ 4-35 คือนิยามคลาส List ซึ่งมีคลาส Node ซ้อนอยู่ภายใน (บรรทัดที่ 10)
คลาส Node มีสมาชิกแบบฟิลด์อยู่เพียงสองตัวทำให้ดูเหมือนเป็นการใช้งานแบบ struc แต่ไม่จำเป็นต้องเป็นเช่นนั้น
เพราะเราอาจใส่สมาชิกแบบอื่น ๆ เช่นเมธอดและพอร์พเพอร์ตีในคลาส Node ได้เหมือนคลาสทั่วไป
โปรดสังเกตว่าเรากำหนดเอกเซสโมดิไฟเออร์ของคลาส Node ให้เป็นไปรเวทแต่กำหนดให้สมาชิกของมันเป็นพับลิก
บรรทัด 11-12 แสดงการประกาศดาต้าฟิลด์ที่มีไทป์เป็น Node
บรรทัดที่ 14-18 คือเมธอดคอนสตรักเตอร์ (constructor method) ของคลาส List จะเห็นการนำคลาส Node มาสร้างเป็นออพเจ็กต์สองตัว
บรรทัด 19-34 คือเมธอด Insert ทำหน้าที่เพิ่มโหนดใหม่เข้าไปในลิสต์ ในนี้จะเห็นการนำออพเจ็กต์ที่ถูกสร้างจากคลาส Node มาใช้งานสามตัวคือ n, head และ tail
บรรทัด 37-46 คือคลาส Program มีโค้ดที่แสดงการนำคลาส List มาสร้างออพเจ็กต์เพื่อใช้งานในบรรทัดที่ 41
โปรดสังเกตว่าคลาส Program จะมองเห็นคลาส List แต่มองไม่เห็นคลาส Node
บรรทัด 42-44 เรียกเมธอด Insert ของออพเจ็กต์ myList เพื่อเพิ่มโหนดใหม่เข้าไปในลิสต์ได้โดยไม่ต้องอ้างถึงคลาส Node เลย
ในตัวอย่างโค้ดที่ยกมานี้คลาส List มีภาวะเป็นคลาสภายนอก (outer class หรือ containing class)
ส่วนคลาส Node มีภาวะเป็นคลาสภายใน (nested class) ซี่งจะมีสถานะเป็นไปรเวทโดยปริยายเพื่อให้ถูกเรียกใช้จากภายนอกไม่ได้
แต่ท่านสามารถเปลี่ยนแปลงเอกเซสโมดิไฟเออร์ของมันให้เป็น public, protected, internal, protected internal หรือ private protected ก็ได้ตามต้องการ