การเขียนโปรแกรมแบบวัตถุวิธีในภาษาซีชาร์ป (OOP with C#) ตอนที่ 4

การเขียนโปรแกรมแบบวัตถุวิธีในภาษาซีชาร์ป (OOP with C#) ตอนที่ 4
ในตอนที่ผ่านมาผู้เขียนได้พูดถึงพรอพเพอร์ตี้ (property) โดยละเอียด และได้พาดพิงถึงหลักการที่เกี่ยวข้องกับคลาสสิกพรอพเพอร์ตี้
อาทิ สมาชิกแบบฟิลด์, เอนเคปซูเลชัน, การเชื่อมหลวมและเกตเตอร์/เซตเตอร์
ในบทความตอนนี้ผู้เขียนจะพูดถึงแง่มุมต่าง ๆ ของการเขียนโค้ดใช้งานพรอพเพอร์ตี้
เช่นวิธีใส่โค้ดคัดกรองข้อมูลในคลาสสิกพรอพเพอร์ตี้ ,วิธีเขียนและใช้งาน “ออโตพรอพเพอร์ตี้” (auto implemented properties)
และวิธีลดทอนพรอพเพอร์ตี้ด้วย “นิพจน์ฝังตัว” (Expression-bodied members) ที่มีประโยชน์มาก เพราะจะช่วยให้การเขียนโค้ดกระชับขึ้นไปอีก
โค้ดคัดกรองข้อมูลในคลาสสิกพรอพเพอร์ตี้
ในบทความตอนที่แล้วผู้เขียนแสดงการคัดกรองข้อมูลในพรอพเพอร์ตี้ฝั่งเก็ต ส่วนในหัวข้อนี้ผู้เขียนจะแสดงตัวอย่างการคัดกรองในฝั่งเซตบ้างโค้ดในภาพที่หนึ่งคือคลาสชื่อ Date คลาสนี้มีพรอพเพอร์ตี้ชื่อ Month
พรอพเพอร์ตี้นี้ทำหน้าที่ช่วยให้โค้ดภายนอกสามารถอ่านเขียนฟิลด์ชื่อ month ได้
เราเรียกฟิลด์ที่มีลักษณะเช่นนี้ว่า แบคกิ้งฟิลด์ (backing fields) คือเป็นฟิลด์ปลายทางที่ทำงานร่วมกับพรอพเพอร์ตี้
โค้ดแสดงตัวอย่างการคัดกรองข้อมูลในพรอพเพอร์ตี้ฝั่งเก็ต
โค้ดซึ่งทำหน้าที่คัดกรองอยู่ที่บรรทัดที่ 13 โดยมีส่วนสำคัญคือนิพจน์ที่อยู่ในวงเล็บหลังคำสั่ง if ((value > 0) && (value < 13))
นิพจน์นี้ทำหน้าที่ให้เรามั่นใจว่า ฟิลด์ month จะไม่ถูกปรับปรุงค่า เว้นเสียแต่ว่าโค้ดภายนอกจะส่งค่าเดือนมาระหว่างหนึ่งถึงสิบสองเท่านั้น
ทำให้เราสามารถส่งค่าของตัวแปรโดยใช้การอ้างอิง (Pass by Reference ย่อ PR) ไปยังเมธอดได้ แต่เราจะทำเช่นนั้นกับพรอพเพอร์ตี้ไม่ได้
ในภาษาซีชาร์พเราสามารถส่งค่าของตัวแปรไปยังเมธอดได้สองแบบคือส่งแบบ PR และส่งแบบคัดลอกค่าในหน่วยความจำไป (Pass by Value ย่อ PV)
ความแตกต่างระหว่าง Pass by Reference กับ Pass by Value
นิพจน์นี้ทำหน้าที่ให้เรามั่นใจว่า ฟิลด์ month จะไม่ถูกปรับปรุงค่า เว้นเสียแต่ว่าโค้ดภายนอกจะส่งค่าเดือนมาระหว่างหนึ่งถึงสิบสองเท่านั้น
วิธีใช้พรอพเพอร์ตี้ไม่เหมือนตัวแปร
ตัวแปรมีสถานที่เก็บข้อมูลอยู่ในหน่วยความจำขณะที่พรอพเพอร์ตี้ไม่มีความแตกต่างนี้ทำให้เราสามารถส่งค่าของตัวแปรโดยใช้การอ้างอิง (Pass by Reference ย่อ PR) ไปยังเมธอดได้ แต่เราจะทำเช่นนั้นกับพรอพเพอร์ตี้ไม่ได้
ในภาษาซีชาร์พเราสามารถส่งค่าของตัวแปรไปยังเมธอดได้สองแบบคือส่งแบบ PR และส่งแบบคัดลอกค่าในหน่วยความจำไป (Pass by Value ย่อ PV)
ความแตกต่างระหว่าง Pass by Reference กับ Pass by Value
จากรูปข้างบนแสดงความแตกต่างระหว่าง PR กับ PV
การส่งค่าไปยังเมธอดด้วยวิธี PV เป็นวิธีปรกติที่เราใช้อยู่เป็นนิจ
การทำเช่นนี้ “ค่าที่อยู่ในหน่วยความจำที่อ้างอิงโดยตัวแปร” (ย่อ mem) จะถูกคัดลอกส่งไปให้เมธอด
หากเมธอดเปลี่ยนแปลงค่านี้ ค่า mem จะไม่เปลี่ยนแปลงตามไปด้วย (เพราะเป็นการเปลี่ยนแปลงแค่สำเนา)
ส่วนการส่งแบบ PR เราไม่ได้ส่งค่า mem ไป แต่เราส่งค่า “ตำแหน่งของหน่วยความจำที่อ้างอิงโดยตัวแปร” (ย่อ ref ใครที่เคยเขียนซี ให้นึกถึงพอยน์เตอร์) ไปให้เมธอด
เมื่อเมธอดได้รับค่า ref แล้วมันจะสามารถเข้าถึงค่า mem เองได้ และสามารถแก้ไขเปลี่ยนแปลงค่า mem ได้ด้วย
โค้ดแสดงความแตกต่างระหว่างพรอพเพอร์ตี้กับตัวแปร
การส่งค่าไปยังเมธอดด้วยวิธี PV เป็นวิธีปรกติที่เราใช้อยู่เป็นนิจ
การทำเช่นนี้ “ค่าที่อยู่ในหน่วยความจำที่อ้างอิงโดยตัวแปร” (ย่อ mem) จะถูกคัดลอกส่งไปให้เมธอด
หากเมธอดเปลี่ยนแปลงค่านี้ ค่า mem จะไม่เปลี่ยนแปลงตามไปด้วย (เพราะเป็นการเปลี่ยนแปลงแค่สำเนา)
ส่วนการส่งแบบ PR เราไม่ได้ส่งค่า mem ไป แต่เราส่งค่า “ตำแหน่งของหน่วยความจำที่อ้างอิงโดยตัวแปร” (ย่อ ref ใครที่เคยเขียนซี ให้นึกถึงพอยน์เตอร์) ไปให้เมธอด
เมื่อเมธอดได้รับค่า ref แล้วมันจะสามารถเข้าถึงค่า mem เองได้ และสามารถแก้ไขเปลี่ยนแปลงค่า mem ได้ด้วย
โค้ดแสดงความแตกต่างระหว่างพรอพเพอร์ตี้กับตัวแปร
โค้ดถัดไปแสดงให้เห็นว่าการทำ PR เราไม่สามารถใช้งานพรอพเพอร์ตี้ได้แบบตัวแปร ให้ดูที่นิยามคลาส foo
บรรทัดที่ 22 ประกาศตัวแปรชื่อ myDate ซึ่งเป็นตัวแปรที่มีชนิดข้อมูลเป็น Date
ซึ่งเป็นคลาสที่เรานิยามไว้ก่อนหน้านี้
บรรทัดที่ 23-27 คือนิยามพรอพเพอร์ตี้ MyDate ที่เราจะใช้คู่กันกับตัวแปร myDate
โปรดสังเกตบรรทัดที่ 25, 26 ว่าเป็นวิธีมาตรฐานในเขียนเกตเซ็ตแบบสั้นที่สุดของคลาสสิกพรอพเพอร์ตี้
บรรทัด 28 คือนิยามเมธอด k ซึ่งมีพารามิเตอร์แบบแวลูไทป์ (value type) หนึ่งตัวชื่อ d
บรรทัด 29 คือนิยามเมธอด f ซึ่งมีพารามิเตอร์แบบรีเฟอร์เรนไทป์ (reference type) หนึ่งตัวชื่อ r
บรรทัด 30-36 คือนิยามเมธอด test ซึ่งเป็นเมธอดที่เราจะใช้ทดสอบการใช้งานตัวแปรและพรอพเพอร์ตี้ในการส่งค่าไปยังเมธอด k และ f
บรรทัด 32 ส่งค่าของตัวแปร myDate ไปเป็นอาร์กิวเมนต์แบบแวลูไทป์ให้แก่เมธอด k สามารถคอมไพล์ได้อย่างไม่มีปัญหา
บรรทัด 33 ส่งค่าของพรอพเพอร์ตี้ MyDate ไปเป็นอาร์กิวเมนต์แบบแวลูไทป์ให้แก่เมธอด k ก็สามารถคอมไพล์ได้อย่างไม่มีปัญหาเช่นกัน
บรรทัด 34 ส่งค่าของตัวแปร myDate ไปเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ให้แก่เมธอด f สามารถคอมไพล์ได้อย่างไม่มีปัญหา
แต่บรรทัด 35 เมื่อส่งค่าของพรอพเพอร์ตี้ MyDate ไปเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ให้แก่เมธอด f จะไม่สามารถคอมไพล์ได้
แสดงให้เห็นว่าพรอพเพอร์ตี้ไม่เหมือนตัวแปร เราจะส่งค่าของพรอพเพอร์ตี้ไปให้เมธอดเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ไม่ได้
เราจะนิยามพรอพเพอร์ตี้ชนิดนี้เมื่อต้องการให้โค้ดภายนอกอ่านค่าบางค่าจากออพเจ็กต์ได้
แต่ไม่สามารถเปลี่ยนแปลงค่านั้นได้ วิธีนิยามพรอพเพอร์ตี้แบบอ่านได้อย่างเดียวเป็นดังนี้
พรอพเพอร์ตี้แบบอ่านได้อย่างเดียว
บรรทัดที่ 22 ประกาศตัวแปรชื่อ myDate ซึ่งเป็นตัวแปรที่มีชนิดข้อมูลเป็น Date
ซึ่งเป็นคลาสที่เรานิยามไว้ก่อนหน้านี้
บรรทัดที่ 23-27 คือนิยามพรอพเพอร์ตี้ MyDate ที่เราจะใช้คู่กันกับตัวแปร myDate
โปรดสังเกตบรรทัดที่ 25, 26 ว่าเป็นวิธีมาตรฐานในเขียนเกตเซ็ตแบบสั้นที่สุดของคลาสสิกพรอพเพอร์ตี้
บรรทัด 28 คือนิยามเมธอด k ซึ่งมีพารามิเตอร์แบบแวลูไทป์ (value type) หนึ่งตัวชื่อ d
บรรทัด 29 คือนิยามเมธอด f ซึ่งมีพารามิเตอร์แบบรีเฟอร์เรนไทป์ (reference type) หนึ่งตัวชื่อ r
บรรทัด 30-36 คือนิยามเมธอด test ซึ่งเป็นเมธอดที่เราจะใช้ทดสอบการใช้งานตัวแปรและพรอพเพอร์ตี้ในการส่งค่าไปยังเมธอด k และ f
บรรทัด 32 ส่งค่าของตัวแปร myDate ไปเป็นอาร์กิวเมนต์แบบแวลูไทป์ให้แก่เมธอด k สามารถคอมไพล์ได้อย่างไม่มีปัญหา
บรรทัด 33 ส่งค่าของพรอพเพอร์ตี้ MyDate ไปเป็นอาร์กิวเมนต์แบบแวลูไทป์ให้แก่เมธอด k ก็สามารถคอมไพล์ได้อย่างไม่มีปัญหาเช่นกัน
บรรทัด 34 ส่งค่าของตัวแปร myDate ไปเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ให้แก่เมธอด f สามารถคอมไพล์ได้อย่างไม่มีปัญหา
แต่บรรทัด 35 เมื่อส่งค่าของพรอพเพอร์ตี้ MyDate ไปเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ให้แก่เมธอด f จะไม่สามารถคอมไพล์ได้
แสดงให้เห็นว่าพรอพเพอร์ตี้ไม่เหมือนตัวแปร เราจะส่งค่าของพรอพเพอร์ตี้ไปให้เมธอดเป็นอาร์กิวเมนต์แบบรีเฟอร์เรนไทป์ไม่ได้
พรอพเพอร์ตี้แบบอ่านได้อย่างเดียว
พรอพเพอร์ตี้แบบอ่านได้อย่างเดียว (Read-only property) คือพรอพเพอร์ตี้ที่มีแต่เกตไม่มีเซตเราจะนิยามพรอพเพอร์ตี้ชนิดนี้เมื่อต้องการให้โค้ดภายนอกอ่านค่าบางค่าจากออพเจ็กต์ได้
แต่ไม่สามารถเปลี่ยนแปลงค่านั้นได้ วิธีนิยามพรอพเพอร์ตี้แบบอ่านได้อย่างเดียวเป็นดังนี้
พรอพเพอร์ตี้แบบอ่านได้อย่างเดียว
บรรทัด 39-49 คือนิยามคลาส Person ในคลาสนี้มีฟิลด์ชื่อ name และมีพรอพเพอร์ตี้ที่คู่กันชื่อ Name
โปรดสังเกตว่านิยามของพรอพเพอร์ตี้นี้มีแต่ส่วนเกตไม่มีส่วนเซต มีผลให้โค้ดภายนอกอ่านค่าของ name ได้แต่ไม่สามารถเปลี่ยนแปลงมันได้
แต่การที่เราสามารถทำได้ไม่ได้หมายความว่าควรทำ พรอพเพอร์ตี้ส่วนเกตควรทำหน้าที่ให้โค้ดภายนอกอ่านค่าได้เท่านั้น
การใส่โค้ดที่ทำให้เกิดความเปลี่ยนแปลงต่อค่าของออพเจ็กต์นับว่าเป็นสไตล์การเขียนโค้ดที่ไม่ดี ลองดูตังอย่างโค้ดต่อไปนี้
การใส่โค้ดในเกตให้เปลี่ยนค่านับว่าไม่ดี
โปรดสังเกตว่านิยามของพรอพเพอร์ตี้นี้มีแต่ส่วนเกตไม่มีส่วนเซต มีผลให้โค้ดภายนอกอ่านค่าของ name ได้แต่ไม่สามารถเปลี่ยนแปลงมันได้
อย่าเปลี่ยนแปลงค่าออพเจ็กต์ด้วยเกตเตอร์
เราอาจใส่โค้ดไว้ภายในพรอพเพอร์ตี้ส่วนเกตให้เกิดความเปลี่ยนแปลงต่อค่าของออพเจ็กต์ได้แต่การที่เราสามารถทำได้ไม่ได้หมายความว่าควรทำ พรอพเพอร์ตี้ส่วนเกตควรทำหน้าที่ให้โค้ดภายนอกอ่านค่าได้เท่านั้น
การใส่โค้ดที่ทำให้เกิดความเปลี่ยนแปลงต่อค่าของออพเจ็กต์นับว่าเป็นสไตล์การเขียนโค้ดที่ไม่ดี ลองดูตังอย่างโค้ดต่อไปนี้
การใส่โค้ดในเกตให้เปลี่ยนค่านับว่าไม่ดี
บรรทัดที่ 61-71 คือนิยามคลาส Bar ในคลาสนี้มีตัวแปร number และพรอพเพอร์ตี้ Number ที่คู่กัน
ส่วนที่ควรสังเกตคือบรรทัด 68 อันเป็นส่วนเกตของพรอพเพอร์ตี้ Number
เมื่อเขียนโค้ดเช่นนี้จะมีผลให้ทุกครั้งที่โค้ดภายนอกเรียกใช้พรอพเพอร์ตี้นี้ ค่าของฟิลด์ number จะเพิ่มขึ้นเสมอไป
แน่นอนว่าผู้ที่นำคลาสนี้ไปใช้ย่อมจะประหลาดใจเพราะไม่เข้าใจว่าค่าของ number เพิ่มขึ้นได้อย่างไร นี่คือลักษณะของบักที่หาต้นตอได้ยาก
ก่อนจะใช้งานพรอพเพอร์ตี้ได้เราต้องนำคลาสไปสร้างออพเจ็กต์เสียก่อน แต่ไม่จำเป็นต้องเป็นเช่นนั้นเสมอไป
เราสามารถใส่พรอพเพอร์ตี้ไว้ในสเตติกคลาสก็ได้ ซึ่งจะมีผลให้โค้ดภายนอกสามารถใช้งานพรอพเพอร์ตี้นั้นได้โดยไม่ต้องนำคลาสไปสร้างออพเจ็กต์ก่อน
ส่วนที่ควรสังเกตคือบรรทัด 68 อันเป็นส่วนเกตของพรอพเพอร์ตี้ Number
เมื่อเขียนโค้ดเช่นนี้จะมีผลให้ทุกครั้งที่โค้ดภายนอกเรียกใช้พรอพเพอร์ตี้นี้ ค่าของฟิลด์ number จะเพิ่มขึ้นเสมอไป
แน่นอนว่าผู้ที่นำคลาสนี้ไปใช้ย่อมจะประหลาดใจเพราะไม่เข้าใจว่าค่าของ number เพิ่มขึ้นได้อย่างไร นี่คือลักษณะของบักที่หาต้นตอได้ยาก
สเตติกพรอพเพอร์ตี้
พรอพเพอร์ตี้ที่ผู้เขียนว่ามาตั้งแต่ตนจนถึงตอนนี้ เป็นพรอพเพอร์ตี้ที่อยู่ในคลาสธรรมดาก่อนจะใช้งานพรอพเพอร์ตี้ได้เราต้องนำคลาสไปสร้างออพเจ็กต์เสียก่อน แต่ไม่จำเป็นต้องเป็นเช่นนั้นเสมอไป
เราสามารถใส่พรอพเพอร์ตี้ไว้ในสเตติกคลาสก็ได้ ซึ่งจะมีผลให้โค้ดภายนอกสามารถใช้งานพรอพเพอร์ตี้นั้นได้โดยไม่ต้องนำคลาสไปสร้างออพเจ็กต์ก่อน
บรรทัด 73-81 คือนิยามคลาส Student ซึ่งเป็นสเตติกคลาส บรรทัด 75 เป็นฟิลด์สมาชิก
บรรทัด 76-80 คือพรอพเพอร์ตี้ โปรดสังเกตว่าเนื่องจาก Student เป็นสเตติกคลาส ฟิลด์และพรอพเพอร์ตี้สมาชิกจึงต้องเป็นสเตติกไปด้วย
บรรทัด 83-86 คือนิยามคลาส School บรรทัด 85 มีโค้ดที่เรียกหาพรอพเพอร์ตี้ Age ของคลาส Student โดยที่เราไม่ได้สร้องออพเจ็กต์ใด ๆ เลย
ข้อควรระวังเกี่ยวกับสเตติกพรอพเพอร์ตี้คือมันจะอ้างอิงไปยังเหล่งเก็บข้อมูลเพียงตัวเดียว ไม่ว่ามันจะถูกเรียกหาจากโค้ดใด ๆ
การกระทำจะเกิดขึ้นกับข้อมูลชุดตัวเดียวกัน ไม่เหมือนคลาสที่ไม่ใช่สเตติก (อินสแตนซ์คลาส) ที่แต่ละออพเจ็กต์แต่ละตัวจะมีที่เก็บข้อมูลเป็นของตัวเองในแต่ละอินสแตนซ์ ไม่ปะปนกัน
คำตอบคือได้ โค้ดตัวอย่างต่อไปนี้แสดงคลาส Employee ที่มีพรอพเพอร์ตี้ที่ว่ามาทั้งสามแบบครบอยู่ภายใน
บรรทัด 76-80 คือพรอพเพอร์ตี้ โปรดสังเกตว่าเนื่องจาก Student เป็นสเตติกคลาส ฟิลด์และพรอพเพอร์ตี้สมาชิกจึงต้องเป็นสเตติกไปด้วย
บรรทัด 83-86 คือนิยามคลาส School บรรทัด 85 มีโค้ดที่เรียกหาพรอพเพอร์ตี้ Age ของคลาส Student โดยที่เราไม่ได้สร้องออพเจ็กต์ใด ๆ เลย
ข้อควรระวังเกี่ยวกับสเตติกพรอพเพอร์ตี้คือมันจะอ้างอิงไปยังเหล่งเก็บข้อมูลเพียงตัวเดียว ไม่ว่ามันจะถูกเรียกหาจากโค้ดใด ๆ
การกระทำจะเกิดขึ้นกับข้อมูลชุดตัวเดียวกัน ไม่เหมือนคลาสที่ไม่ใช่สเตติก (อินสแตนซ์คลาส) ที่แต่ละออพเจ็กต์แต่ละตัวจะมีที่เก็บข้อมูลเป็นของตัวเองในแต่ละอินสแตนซ์ ไม่ปะปนกัน
การใช้หลายแบบร่วมกัน
เราใส่พรอพเพอร์ตี้แบบอินสแตนส์, แบบสเตติก, และแบบอ่านได้อย่างเดียวไว้ในคลาสเดียวกันได้หรือไม่คำตอบคือได้ โค้ดตัวอย่างต่อไปนี้แสดงคลาส Employee ที่มีพรอพเพอร์ตี้ที่ว่ามาทั้งสามแบบครบอยู่ภายใน
บรรทัดที่ 16-41 คือนิยามคลาส Employee ซึ่งเป็นคลาสที่มีพรอพเพอร์ตี้ในรูปแบบต่าง ๆ ที่กล่าวถึงข้างต้น
บรรทัด 43-54 คือนิยามคลาส TestEmployee ซึ่งเป็นคลาสที่จะใช้ทำหน้าที่ทดสอบการใช้งานพรอพเพอร์ตี้ชนิดต่าง ๆ ที่อยู่ภายในคลาส Employee
บรรทัด 18 คือการประกาศฟิลด์สมาชิก NumberOfEmployees ใช้เก็บเลขลำดับที่ของพนักงาน
โปรดสังเกตว่าฟิลด์นี้มีเอกเซสโมดิไฟเออร์สองตัว คือ public และ static มีผลให้โค้ดภายนอกสามารถมองเห็นฟิลด์นี้ได้โดยไม่ต้องสร้างออพเจ็กต์จากคลาสนี้เสียก่อน
ทำให้มันมีภาวะเป็นตัวแปรประจำคลาส (ไม่ใช่ตัวแปรประจำออพเจ็กต์)
บรรทัด 19 คือการประกาศฟิลด์สมาชิก counter ใช้เก็บจำนวนพนักงาน โปรดสังเกตว่าฟิลด์นี้มีเอกเซสโมดิไฟเออร์สองตัว คือ private และ static มีผลให้โค้ดภายนอกไม่สามารถมองเห็นฟิลด์นี้ได้
ดังนั้นเราจะประกาศพรอพเพอร์ตี้มาใช้คู่กับฟิลด์นี้ แต่การที่มันเป็นสเตติกทำให้มันมีภาวะเป็นตัวแปรประจำคลาส (ไม่ใช่ตัวแปรประจำออพเจ็กต์) เช่นเดียวกับ ฟิลด์สมาชิก NumberOfEmployees
บรรทัด 20 คือการประกาศฟิลด์สมาชิก name ใช้เก็บชื่อพนักงาน เนื่องจากฟิลด์นี้เป็นแบบ private ทำให้มันมีภาวะเป็นตัวแปรประจำออพเจ็กต์ ไม่ได้เป็นตัวแปรประจำคลาสอย่างสองตัวแรก
บรรทัด 23-27 คือการประกาศพรอพเพอร์ตี้ชื่อ Name ที่มีแบคกิ้งฟิลด์เป็นฟิลด์ name เนื่องจากมันมีโค้ดทั้งเกตและเซตทำให้โค้ดภายนอกสามารถอ่านและเขียนค่าของพรอพเพอร์ตี้นี้ได้
บรรทัด 30-33 คือการประกาศพรอพเพอร์ตี้ชื่อ Counter มีแบคกิ้งฟิลด์เป็นฟิลด์ counter
เนื่องจากมันมีโค้ดเฉพาะเกตไม่มีเซต ทำให้โค้ดภายนอกสามารถอ่านค่าของพรอพเพอร์ตี้นี้ได้แต่เขียนไม่ได้
สาเหตุที่ทำเช่นนี้เพราะเราต้องการให้ counter เพิ่มค่าก็ต่อเมื่อมีการสร้างออพเจ็กต์ใหม่จากคลาสนี้เท่านั้น
และการเพิ่มค่านี้เกิดขึ้นจากกลไกภายในออพเจ็กต์เอง ไม่ต้องการให้โค้ดภายนอกเปลี่ยนแปลงมัน
บรรทัด 36-40 คือเมธอดคอนสทรักเตอร์ เมธอดนี้จะถูกเรียกให้ทำงานเมื่อโค้ดภายนอกใช้ตัวกระทำ new ต่อคลาสนี้
บรรทัด 39 คำนวณเลขที่ของพนักงานโดยนำค่าจาก NumberOfEmployees มาบวกกับ counter
เนื่องจากมีตัวกระทำ ++ อยู่หน้าตัวแปร counter มีผลให้ค่าของ counter เพิ่มขึ้นก่อนที่มันจะถูกนำไปบวกกับ NumberOfEmployees
ดังนั้นหาก NumberOfEmployees มีค่า 107 เมื่อคำสั่งบรรทัดนี้ทำงานจะมีผลให้ counter มีค่าเป็น 108
บรรทัด 48 กำหนดค่าให้ NumberOfEmployees เป็น 107 โปรดสังเกตว่านี่คือตัวแปรของคลาส
ดังนั้นถ้ามีโค้ดภายนอกหลายแห่งที่นำคลาสนี้ไปสร้างออพเจ็กต์หลาย ๆ ออพเจ็กต์และเปลี่ยนแปลงค่านี้จากในตำแหน่งต่าง ๆ หลายตำแหน่ง
ค่านี้จะถูกใช้ร่วมกันจากทุกแห่ง บรรทัด 48 สร้างออพเจ็กต์ใหม่จากคลาส Employee โดยมีตัวแปร e1 ไว้ใช้อ้างอิง
บรรทัด 49 กำหนดค่าให้พรอพเพอร์ตี้ Name เป็น Toon Runner โปรดสังเกตว่าการทำเช่นนี้จะส่งผลให้ค่าของฟิลด์ name
ซึ่งเป็นตัวแปรของออพเจ็กต์เปลี่ยนไป ดังนั้นถ้ามีโค้ดภายนอกหลายแห่งนำคลาสนี้ไปสร้างออพเจ็กต์หลาย ๆ ออพเจ็กต์
และเปลี่ยนแปลงค่านี้จากในตำแหน่งต่าง ๆ หลายตำแหน่ง ฟิลด์นี้จะมีค่าแยกกันเป็นคนละตัวทั้งหมด
บรรทัด 51 พิมพ์ค่าของพรอพเพอร์ตี้ Counter นี่คือโค้ดแสดงตัวอย่างการอ่านค่าโดยทางอ้อมจากฟิลด์ counter
บรรทัด 52 พิมพ์ค่าของพรอพเพอร์ตี้ Name นี่คือโค้ดแสดงตัวอย่างการอ่านค่าโดยทางอ้อมจากฟิลด์ name เช่นกัน
โปรดสังเกตว่าการอ่านค่าจากพรอพเพอร์ตี้ที่เป็นสเตติก (Counter) เขียนโค้ดต่างจากการอ่านพรอพเพอร์ตี้ที่เป็นอินสแตนซ์ (Name)
การอ่านค่าจากพรอพเพอร์ตี้ที่เป็นสเตติกทำได้โดยระบุชื่อคลาส ตามตัวเครื่องหมายจุด และตามด้วยชื่อพรอพเพอร์ตี้
ขณะที่การอ่านค่าจากพรอพเพอร์ตี้ที่เป็นอินสแตนซ์ทำได้โดยระบุชื่อออพเจ็กต์ ตามตัวเครื่องหมายจุด และตามด้วยชื่อพรอพเพอร์ตี้
แต่เราจะใช้วิธีสร้างคลาสใหม่แล้วดึงคุณสมบัติต่าง ๆ จากคลาสที่นิยามไว้แล้วมาใช้
ยกตัวอย่างเช่นในโค้ดตัวอย่างก่อนหน้านี้เรานิยามคลาส Employee เพื่อทำหน้าที่เป็นพนักงาน
ต่อมาเรามีพนักงานแบบใหม่คือผู้จัดการ (Manager) ที่มีคุณสมบัติทุกอย่างเหมือน Employee ธรรมดา แต่มีคุณสมบัติใหม่เพิ่มเข้ามา
ในกรณีนี้เราจะไม่ไปแก้ไขคลาส Employee เพื่อเพิ่มคุณสมบัติใหม่นี้เข้าไป
แต่เราจะใช้วิธีนิยามคลาสใหม่ชื่อ Manager ที่สืบคุณสมบัติมาจาก Employee ทั้งหมด
จากนั้นใส่โค้ดเพื่อเพิ่มคุณสมบัติใหม่เข้าไปในคลาสนี้
การทำเช่นนี้คือหลักการ อินเฮียริแตนซ์ ที่ผู้เขียนจะอธิบายรายละเอียดในตอนต่อ ๆ ไป
ส่วนในบทความตอนนี้จะเน้นเฉพาะพรอพเพอร์ตี้
ปัญหาคือบ่อยครั้งที่สมาชิกของคลาสแม่ที่เราต้องการเปลี่ยนแปลงคุณสมบัติไม่ได้ถูกเขียนไว้ให้เราทำได้ง่าย ๆ
วิธีแก้คือซ่อนสมาชิกตัวนั้นโดยใส่นิยามใหม่ทับลงไปในคลาสลูก ดูตัวอย่างการทำในโค้ดต่อไปนี้
การซ่อนพอรอเพอร์ตี
บรรทัด 43-54 คือนิยามคลาส TestEmployee ซึ่งเป็นคลาสที่จะใช้ทำหน้าที่ทดสอบการใช้งานพรอพเพอร์ตี้ชนิดต่าง ๆ ที่อยู่ภายในคลาส Employee
บรรทัด 18 คือการประกาศฟิลด์สมาชิก NumberOfEmployees ใช้เก็บเลขลำดับที่ของพนักงาน
โปรดสังเกตว่าฟิลด์นี้มีเอกเซสโมดิไฟเออร์สองตัว คือ public และ static มีผลให้โค้ดภายนอกสามารถมองเห็นฟิลด์นี้ได้โดยไม่ต้องสร้างออพเจ็กต์จากคลาสนี้เสียก่อน
ทำให้มันมีภาวะเป็นตัวแปรประจำคลาส (ไม่ใช่ตัวแปรประจำออพเจ็กต์)
บรรทัด 19 คือการประกาศฟิลด์สมาชิก counter ใช้เก็บจำนวนพนักงาน โปรดสังเกตว่าฟิลด์นี้มีเอกเซสโมดิไฟเออร์สองตัว คือ private และ static มีผลให้โค้ดภายนอกไม่สามารถมองเห็นฟิลด์นี้ได้
ดังนั้นเราจะประกาศพรอพเพอร์ตี้มาใช้คู่กับฟิลด์นี้ แต่การที่มันเป็นสเตติกทำให้มันมีภาวะเป็นตัวแปรประจำคลาส (ไม่ใช่ตัวแปรประจำออพเจ็กต์) เช่นเดียวกับ ฟิลด์สมาชิก NumberOfEmployees
บรรทัด 20 คือการประกาศฟิลด์สมาชิก name ใช้เก็บชื่อพนักงาน เนื่องจากฟิลด์นี้เป็นแบบ private ทำให้มันมีภาวะเป็นตัวแปรประจำออพเจ็กต์ ไม่ได้เป็นตัวแปรประจำคลาสอย่างสองตัวแรก
บรรทัด 23-27 คือการประกาศพรอพเพอร์ตี้ชื่อ Name ที่มีแบคกิ้งฟิลด์เป็นฟิลด์ name เนื่องจากมันมีโค้ดทั้งเกตและเซตทำให้โค้ดภายนอกสามารถอ่านและเขียนค่าของพรอพเพอร์ตี้นี้ได้
บรรทัด 30-33 คือการประกาศพรอพเพอร์ตี้ชื่อ Counter มีแบคกิ้งฟิลด์เป็นฟิลด์ counter
เนื่องจากมันมีโค้ดเฉพาะเกตไม่มีเซต ทำให้โค้ดภายนอกสามารถอ่านค่าของพรอพเพอร์ตี้นี้ได้แต่เขียนไม่ได้
สาเหตุที่ทำเช่นนี้เพราะเราต้องการให้ counter เพิ่มค่าก็ต่อเมื่อมีการสร้างออพเจ็กต์ใหม่จากคลาสนี้เท่านั้น
และการเพิ่มค่านี้เกิดขึ้นจากกลไกภายในออพเจ็กต์เอง ไม่ต้องการให้โค้ดภายนอกเปลี่ยนแปลงมัน
บรรทัด 36-40 คือเมธอดคอนสทรักเตอร์ เมธอดนี้จะถูกเรียกให้ทำงานเมื่อโค้ดภายนอกใช้ตัวกระทำ new ต่อคลาสนี้
บรรทัด 39 คำนวณเลขที่ของพนักงานโดยนำค่าจาก NumberOfEmployees มาบวกกับ counter
เนื่องจากมีตัวกระทำ ++ อยู่หน้าตัวแปร counter มีผลให้ค่าของ counter เพิ่มขึ้นก่อนที่มันจะถูกนำไปบวกกับ NumberOfEmployees
ดังนั้นหาก NumberOfEmployees มีค่า 107 เมื่อคำสั่งบรรทัดนี้ทำงานจะมีผลให้ counter มีค่าเป็น 108
บรรทัด 48 กำหนดค่าให้ NumberOfEmployees เป็น 107 โปรดสังเกตว่านี่คือตัวแปรของคลาส
ดังนั้นถ้ามีโค้ดภายนอกหลายแห่งที่นำคลาสนี้ไปสร้างออพเจ็กต์หลาย ๆ ออพเจ็กต์และเปลี่ยนแปลงค่านี้จากในตำแหน่งต่าง ๆ หลายตำแหน่ง
ค่านี้จะถูกใช้ร่วมกันจากทุกแห่ง บรรทัด 48 สร้างออพเจ็กต์ใหม่จากคลาส Employee โดยมีตัวแปร e1 ไว้ใช้อ้างอิง
บรรทัด 49 กำหนดค่าให้พรอพเพอร์ตี้ Name เป็น Toon Runner โปรดสังเกตว่าการทำเช่นนี้จะส่งผลให้ค่าของฟิลด์ name
ซึ่งเป็นตัวแปรของออพเจ็กต์เปลี่ยนไป ดังนั้นถ้ามีโค้ดภายนอกหลายแห่งนำคลาสนี้ไปสร้างออพเจ็กต์หลาย ๆ ออพเจ็กต์
และเปลี่ยนแปลงค่านี้จากในตำแหน่งต่าง ๆ หลายตำแหน่ง ฟิลด์นี้จะมีค่าแยกกันเป็นคนละตัวทั้งหมด
บรรทัด 51 พิมพ์ค่าของพรอพเพอร์ตี้ Counter นี่คือโค้ดแสดงตัวอย่างการอ่านค่าโดยทางอ้อมจากฟิลด์ counter
บรรทัด 52 พิมพ์ค่าของพรอพเพอร์ตี้ Name นี่คือโค้ดแสดงตัวอย่างการอ่านค่าโดยทางอ้อมจากฟิลด์ name เช่นกัน
โปรดสังเกตว่าการอ่านค่าจากพรอพเพอร์ตี้ที่เป็นสเตติก (Counter) เขียนโค้ดต่างจากการอ่านพรอพเพอร์ตี้ที่เป็นอินสแตนซ์ (Name)
การอ่านค่าจากพรอพเพอร์ตี้ที่เป็นสเตติกทำได้โดยระบุชื่อคลาส ตามตัวเครื่องหมายจุด และตามด้วยชื่อพรอพเพอร์ตี้
ขณะที่การอ่านค่าจากพรอพเพอร์ตี้ที่เป็นอินสแตนซ์ทำได้โดยระบุชื่อออพเจ็กต์ ตามตัวเครื่องหมายจุด และตามด้วยชื่อพรอพเพอร์ตี้
การซ่อนพรอพเพอร์ตี้
หลักการเขียนโปรแกรมแบบ OOP เมื่อเราต้องการต่อยอดงาน เราจะไม่แก้ไขดัดแปลงคลาสที่นิยามไปแล้วแต่เราจะใช้วิธีสร้างคลาสใหม่แล้วดึงคุณสมบัติต่าง ๆ จากคลาสที่นิยามไว้แล้วมาใช้
ยกตัวอย่างเช่นในโค้ดตัวอย่างก่อนหน้านี้เรานิยามคลาส Employee เพื่อทำหน้าที่เป็นพนักงาน
ต่อมาเรามีพนักงานแบบใหม่คือผู้จัดการ (Manager) ที่มีคุณสมบัติทุกอย่างเหมือน Employee ธรรมดา แต่มีคุณสมบัติใหม่เพิ่มเข้ามา
ในกรณีนี้เราจะไม่ไปแก้ไขคลาส Employee เพื่อเพิ่มคุณสมบัติใหม่นี้เข้าไป
แต่เราจะใช้วิธีนิยามคลาสใหม่ชื่อ Manager ที่สืบคุณสมบัติมาจาก Employee ทั้งหมด
จากนั้นใส่โค้ดเพื่อเพิ่มคุณสมบัติใหม่เข้าไปในคลาสนี้
การทำเช่นนี้คือหลักการ อินเฮียริแตนซ์ ที่ผู้เขียนจะอธิบายรายละเอียดในตอนต่อ ๆ ไป
ส่วนในบทความตอนนี้จะเน้นเฉพาะพรอพเพอร์ตี้
ปัญหาคือบ่อยครั้งที่สมาชิกของคลาสแม่ที่เราต้องการเปลี่ยนแปลงคุณสมบัติไม่ได้ถูกเขียนไว้ให้เราทำได้ง่าย ๆ
วิธีแก้คือซ่อนสมาชิกตัวนั้นโดยใส่นิยามใหม่ทับลงไปในคลาสลูก ดูตัวอย่างการทำในโค้ดต่อไปนี้
การซ่อนพอรอเพอร์ตี
บรรทัด 9-17 คือคลาส Employee เหมือนในตัวอย่างที่ผ่านมา คือมีฟิลด์สมาชิกชื่อ name และมีพรอพเพอร์ตี้ชื่อ Name ที่นิยามไว้ใช้คู่กัน
เอ็กเซสโมดิไฟเออร์ของทั้งสองตัวเป็นไฟรเวทและพับลิกตามลำดับซึ่งเป็นกรณีปรกติพื้นฐานของการประกาศนิยามฟิลด์พรอพเพอร์ตี้
และโปรดสังเกตว่าพรอพเพอร์ตี้มีโค้ดกำหนดเกตเซตครบตามมาตรฐานและเป็นชนิดที่สั้นที่สุด
บรรทัด 19-29 คือคลาส Manager เป็นคลาสที่สืบคุณสมบัติ (derived class) จากคลาส Employee มีผลให้คลาส Employee มีฐานะเป็นคลาสฐาน (base class) หรือคลาสแม่ (parent class)
โปรดสังเกตตัวกระทำ : ในบรรทัดที่ 19 ตัวกระทำนี้มีผลให้สิ่งที่อยู่ทางซ้ายของมันเป็นชื่อคลาสที่กำลังจะนิยาม และสิ่งที่อยู่ทางขวาของมันเป็นชื่อคลาสที่เป็นคลาสฐาน
บรรทัด 21 ประกาศฟิลด์สมาชิกชื่อ name เหมือนกันกับในคลาสแม่ แต่ถือว่าเป็นตัวแปรคนละตัวกันเพราะมีเอ็กเซสโมดิไฟเออร์เป็นไฟรเวท
บรรทัดที่ 24-28 ประกาศพรอพเพอร์ตี้ชื่อ Name เหมือนในคลาสแม่ เพื่อไม่ให้พรอพเพอร์ตี้ Name ในคลาสลูกตีกันกับพรอพเพอร์ตี้ Name ในคลาสแม่
เราจะต้องซ่อนพรอพเพอร์ตี้ Name ในคลาสแม่โดยใส่โมดิไฟเออร์ new ไว้ในส่วนประกาศพรอพเพอร์ตี้ Name ของคลาสลูก (ดูบรรทัด 24)
บรรทัด 26 ส่วนเกตของพรอพเพอร์ตี้ Name ไม่มีอะไรพิเศษ แต่ส่วนเซต (บรรทัด 27) เรานำชื่อคนที่รับมาแล้วเพิ่มข้อความว่า “, Manager” ต่อท้ายด้วย
เพื่อให้เห็นความแตกต่างว่าคลาสลูกและพรอพเพอร์ตี้ของมันแปลกจากคลาสแม่
บรรทัดที่ 31-46 คือนิยามคลาส TestHiding ทำหน้าที่เป็นโค้ดภายนอกไว้ทดสอบการใช้งานคลาส Employee และคลาส Manager
บรรทัด 35 สร้างออพเจ็กต์จากคลาส Manager บรรทัด 38 อ้างถึงพรอพเพอร์ตี้ Name ที่อยู่ในคลาสลูก
ถึงแม้ว่าเราจะซ่อนพรอพเพอร์ตี้ Name ในคลาสแม่ไว้แล้ว แต่โค้ดภายนอกก็ยังสามารถเรียกหามันได้ด้วยการทำแคสติง (casting)
ดูบรรทัด 41 แสดงวิธีอ้างถึงพรอพเพอร์ตี้ Name ที่เราซ่อนไว้ในคลาสแม่ โปรดสังเกตวงเล็บ (Employee) ที่ใส่ไว้หน้าตัวแปร m1
ซึ่งมีผลให้เกิดการแปลงชนิดข้อมูลจากเดิม m1 มีดาต้าชนิดข้อมูลเป็น Manager ไปเป็นชนิดข้อมูล Employee เมื่อระบุอย่างนี้แล้ว
การอ้างถึงพรอพเพอร์ตี้ Name จะกลายเป็นตัวที่อยู่ใน Employee ไม่ใช่ตัวที่อยู่ใน Manager
ถ้าเราต้องการเพียงแค่ให้โค้ดภายนอกอ่านเขียนค่าของออพเจ็กต์ได้ โดยไม่ต้องการโค้ดส่วนคัดกรองใด ๆ
และต้องการทำพรอพเพอร์ตี้จำนวนมาก อย่างในคลาสที่เราจะใช้ทำหน้าที่เก็บโครงสร้างแบบจำลองตารางในฐานข้อมูล
จำนวนบรรทัดของโค้ดอาจดูมากเกินจำเป็นและรุงรังยืดเยื้อเกินไป
เพื่อแก้ปัญหาดังที่กล่าวมาในย่อหน้าบน
ภาษาซีชาร์พตั้งแต่เวอร์ชั่น 3.0 เป็นต้นมาจึงจัดให้มีกลไกที่เรียกว่า “ออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้” (Auto-Implemented Properties)
ที่ช่วยให้การประกาศพรอพเพอร์ตี้กะทัดรัดขึ้น เพราะพรอพเพอร์ตี้ชนิดนี้ไม่ต้องมีแบ๊กกิ้งฟิลด์และไม่ต้องมีโค้ดเพิ่มเติมในเกตและเซต
เราสามารถเกตและเซตรวบไว้ในวงเล็บปีกกาได้เลย
ออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้
เอ็กเซสโมดิไฟเออร์ของทั้งสองตัวเป็นไฟรเวทและพับลิกตามลำดับซึ่งเป็นกรณีปรกติพื้นฐานของการประกาศนิยามฟิลด์พรอพเพอร์ตี้
และโปรดสังเกตว่าพรอพเพอร์ตี้มีโค้ดกำหนดเกตเซตครบตามมาตรฐานและเป็นชนิดที่สั้นที่สุด
บรรทัด 19-29 คือคลาส Manager เป็นคลาสที่สืบคุณสมบัติ (derived class) จากคลาส Employee มีผลให้คลาส Employee มีฐานะเป็นคลาสฐาน (base class) หรือคลาสแม่ (parent class)
โปรดสังเกตตัวกระทำ : ในบรรทัดที่ 19 ตัวกระทำนี้มีผลให้สิ่งที่อยู่ทางซ้ายของมันเป็นชื่อคลาสที่กำลังจะนิยาม และสิ่งที่อยู่ทางขวาของมันเป็นชื่อคลาสที่เป็นคลาสฐาน
บรรทัด 21 ประกาศฟิลด์สมาชิกชื่อ name เหมือนกันกับในคลาสแม่ แต่ถือว่าเป็นตัวแปรคนละตัวกันเพราะมีเอ็กเซสโมดิไฟเออร์เป็นไฟรเวท
บรรทัดที่ 24-28 ประกาศพรอพเพอร์ตี้ชื่อ Name เหมือนในคลาสแม่ เพื่อไม่ให้พรอพเพอร์ตี้ Name ในคลาสลูกตีกันกับพรอพเพอร์ตี้ Name ในคลาสแม่
เราจะต้องซ่อนพรอพเพอร์ตี้ Name ในคลาสแม่โดยใส่โมดิไฟเออร์ new ไว้ในส่วนประกาศพรอพเพอร์ตี้ Name ของคลาสลูก (ดูบรรทัด 24)
บรรทัด 26 ส่วนเกตของพรอพเพอร์ตี้ Name ไม่มีอะไรพิเศษ แต่ส่วนเซต (บรรทัด 27) เรานำชื่อคนที่รับมาแล้วเพิ่มข้อความว่า “, Manager” ต่อท้ายด้วย
เพื่อให้เห็นความแตกต่างว่าคลาสลูกและพรอพเพอร์ตี้ของมันแปลกจากคลาสแม่
บรรทัดที่ 31-46 คือนิยามคลาส TestHiding ทำหน้าที่เป็นโค้ดภายนอกไว้ทดสอบการใช้งานคลาส Employee และคลาส Manager
บรรทัด 35 สร้างออพเจ็กต์จากคลาส Manager บรรทัด 38 อ้างถึงพรอพเพอร์ตี้ Name ที่อยู่ในคลาสลูก
ถึงแม้ว่าเราจะซ่อนพรอพเพอร์ตี้ Name ในคลาสแม่ไว้แล้ว แต่โค้ดภายนอกก็ยังสามารถเรียกหามันได้ด้วยการทำแคสติง (casting)
ดูบรรทัด 41 แสดงวิธีอ้างถึงพรอพเพอร์ตี้ Name ที่เราซ่อนไว้ในคลาสแม่ โปรดสังเกตวงเล็บ (Employee) ที่ใส่ไว้หน้าตัวแปร m1
ซึ่งมีผลให้เกิดการแปลงชนิดข้อมูลจากเดิม m1 มีดาต้าชนิดข้อมูลเป็น Manager ไปเป็นชนิดข้อมูล Employee เมื่อระบุอย่างนี้แล้ว
การอ้างถึงพรอพเพอร์ตี้ Name จะกลายเป็นตัวที่อยู่ใน Employee ไม่ใช่ตัวที่อยู่ใน Manager
ออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้
ในบางกรณีการประกาศพรอพเพอร์ตี้อาจจะยุ่งยากเกินไป เพราะนอกจากจะต้องทำแบ๊กกิ้งฟิลด์แล้วยังต้องเขียนโค้ดพรอพเพอร์ตี้อีกถ้าเราต้องการเพียงแค่ให้โค้ดภายนอกอ่านเขียนค่าของออพเจ็กต์ได้ โดยไม่ต้องการโค้ดส่วนคัดกรองใด ๆ
และต้องการทำพรอพเพอร์ตี้จำนวนมาก อย่างในคลาสที่เราจะใช้ทำหน้าที่เก็บโครงสร้างแบบจำลองตารางในฐานข้อมูล
จำนวนบรรทัดของโค้ดอาจดูมากเกินจำเป็นและรุงรังยืดเยื้อเกินไป
เพื่อแก้ปัญหาดังที่กล่าวมาในย่อหน้าบน
ภาษาซีชาร์พตั้งแต่เวอร์ชั่น 3.0 เป็นต้นมาจึงจัดให้มีกลไกที่เรียกว่า “ออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้” (Auto-Implemented Properties)
ที่ช่วยให้การประกาศพรอพเพอร์ตี้กะทัดรัดขึ้น เพราะพรอพเพอร์ตี้ชนิดนี้ไม่ต้องมีแบ๊กกิ้งฟิลด์และไม่ต้องมีโค้ดเพิ่มเติมในเกตและเซต
เราสามารถเกตและเซตรวบไว้ในวงเล็บปีกกาได้เลย
ออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้
โปรแกรมตัวอย่างนี้แสดงโค้ดเปรียบเทียบพรอพเพอร์ตี้ธรรมดากับออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้
บรรทัดที่ 14-18 คือพรอพเพอร์ตี้ชื่อ Foo1 ซึ่งเป็นพรอพเพอร์ตี้ธรรมดา
โปรดสังเกตว่าเราต้องประกาศตัวแปรฟิลด์ foo1 (บรรทัดที่ 12) ซึ่งทำหน้าที่เป็นแบ๊กกิ้งฟิลด์ไว้คู่กันกับพรอพเพอร์ตี้ด้วย
บรรทัด 20 คือการประกาศออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้ จะเห็นว่าพรอพเพอร์ตี้ชนิดนี้กระทัดรัดสั้นเพียงบรรทัดเดียว
และไม่ต้องประกาศตัวแปรฟิลด์ foo2 เป็นแบ๊กกิ้งฟิลด์ไว้คู่กัน
โค้ดภายนอกมองเห็นออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้กับพรอพเพอร์ตี้ธรรมดาว่าไม่แตกต่างกัน
มีวิธีเรียกใช้งานได้แบบเดียวกัน
เราสามารถนำการเขียนโค้ดแบบนิพจน์ฝังตัวมาใช้เพี่อประกาศส่วนเกตของพรอพเพอร์ตี้ได้ และในภาษาซีชาร์พตั้งแต่เวอร์ชั่น 7.0 เป็นต้นมา
เราสามารถนำการเขียนโค้ดแบบสมาชิกแบบนิพจน์ฝังตัวมาใช้เพี่อประกาศส่วนเซตของพรอพเพอร์ตี้ได้ด้วย
พรอพเพอร์ตี้แบบนิพจน์ฝังตัว
บรรทัดที่ 14-18 คือพรอพเพอร์ตี้ชื่อ Foo1 ซึ่งเป็นพรอพเพอร์ตี้ธรรมดา
โปรดสังเกตว่าเราต้องประกาศตัวแปรฟิลด์ foo1 (บรรทัดที่ 12) ซึ่งทำหน้าที่เป็นแบ๊กกิ้งฟิลด์ไว้คู่กันกับพรอพเพอร์ตี้ด้วย
บรรทัด 20 คือการประกาศออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้ จะเห็นว่าพรอพเพอร์ตี้ชนิดนี้กระทัดรัดสั้นเพียงบรรทัดเดียว
และไม่ต้องประกาศตัวแปรฟิลด์ foo2 เป็นแบ๊กกิ้งฟิลด์ไว้คู่กัน
โค้ดภายนอกมองเห็นออโต้-อิมพลีเมนเต็ตพรอพเพอร์ตี้กับพรอพเพอร์ตี้ธรรมดาว่าไม่แตกต่างกัน
มีวิธีเรียกใช้งานได้แบบเดียวกัน
พรอพเพอร์ตี้แบบนิพจน์ฝังตัว
ภาษาซีชาร์พตั้งแต่เวอร์ชั่น 6.0 เป็นต้นมาเพิ่มสิ่งที่เรียกว่า “สมาชิกแบบนิพจน์ฝังตัว” (Expression-bodied members) ที่ช่วยให้โค้ดดูกระชับและอ่านง่ายขึ้นเราสามารถนำการเขียนโค้ดแบบนิพจน์ฝังตัวมาใช้เพี่อประกาศส่วนเกตของพรอพเพอร์ตี้ได้ และในภาษาซีชาร์พตั้งแต่เวอร์ชั่น 7.0 เป็นต้นมา
เราสามารถนำการเขียนโค้ดแบบสมาชิกแบบนิพจน์ฝังตัวมาใช้เพี่อประกาศส่วนเซตของพรอพเพอร์ตี้ได้ด้วย
พรอพเพอร์ตี้แบบนิพจน์ฝังตัว
โปรดสังเกตว่าพรอพเพอร์ตี้แบบนิพจน์ฝังตัวจำเป็นต้องต้องมีตัวแปรฟิลด์ที่ทำหน้าที่เป็นแบ๊กกิ้งฟิลด์ไว้คู่กันกับพรอพเพอร์ตี้ด้วย
และโปรดสังเกตว่าการเกตไม่ต้องใช้คำสั่ง return แต่ใช้ลูกศรอ้วน ( เครื่องหมายเท่ากับและเครื่องหมายมากกว่า =>) ชี้ไปยังแบ๊กกิ้งฟิลด์
ในแง่ประสิทธิภาพพรอพเพอร์ตี้ทั้งสามแบบมีประสิทธิภาพเท่ากันเพราะอันที่จริงแล้วมันคือการแกล้งแต่งให้ดูงามเท่านั้น โค้ดหลังการคอมไพล์ไม่ต่างกัน
ในบทความตอนนี้ท่านได้เรียนเรื่องกลเม็ดในการเขียนโค้ดใช้งานพรอพเพอร์ตี้
อาทิ วิธีใส่โค้ดคัดกรองข้อมูลในคลาสสิกพรอพเพอร์ตี้ พรอพเพอร์ตี้ที่อ่านได้อย่างเดียว
วิธีซ่อนพรอพเพอร์ตี้ และพรอพเพอร์ตี้แบบใหม่ที่ปรากฏในชาร์พเวอร์ชั่นล่าสุด เรื่องพรอพเพอร์ตี้ถือว่าสิ้นสุดเพียงเท่านี้
ในบทความตอนต่อไปผู้เขียนจะนำเสนอแง่มุมสำคัญอื่น ๆ ของหลักการเอ็นแคปซูเลชัน
และโปรดสังเกตว่าการเกตไม่ต้องใช้คำสั่ง return แต่ใช้ลูกศรอ้วน ( เครื่องหมายเท่ากับและเครื่องหมายมากกว่า =>) ชี้ไปยังแบ๊กกิ้งฟิลด์
ในแง่ประสิทธิภาพพรอพเพอร์ตี้ทั้งสามแบบมีประสิทธิภาพเท่ากันเพราะอันที่จริงแล้วมันคือการแกล้งแต่งให้ดูงามเท่านั้น โค้ดหลังการคอมไพล์ไม่ต่างกัน
ในบทความตอนนี้ท่านได้เรียนเรื่องกลเม็ดในการเขียนโค้ดใช้งานพรอพเพอร์ตี้
อาทิ วิธีใส่โค้ดคัดกรองข้อมูลในคลาสสิกพรอพเพอร์ตี้ พรอพเพอร์ตี้ที่อ่านได้อย่างเดียว
วิธีซ่อนพรอพเพอร์ตี้ และพรอพเพอร์ตี้แบบใหม่ที่ปรากฏในชาร์พเวอร์ชั่นล่าสุด เรื่องพรอพเพอร์ตี้ถือว่าสิ้นสุดเพียงเท่านี้
ในบทความตอนต่อไปผู้เขียนจะนำเสนอแง่มุมสำคัญอื่น ๆ ของหลักการเอ็นแคปซูเลชัน