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

ข้อดีของภาษา C# เมื่อเทียบกับภาษาอื่น ๆ
บทความนี้จะอธิบายว่าภาษาซีชาร์พมีข้อดีกว่าภาษาต่าง ๆ อย่างไรบ้าง พร้อมแสดงตัวอย่างโค้ดเพื่อเปรียบเทียบให้เห็นความได้เปรียบนั้นอย่างชัดเจนด้วย
ภาษาซีชาร์พนับเป็นภาษาใหม่อายุน้อยเมื่อเทียบกับภาษาอื่น ๆ ยกตัวอย่าง เช่น เมื่อเทียบกับภาษาซีซึ่งเป็นภาษาเก่าแก่มีอายุมากถึงสี่สิบหกปีแล้ว
หรือเทียบกับภาษา ไพธอน ที่มีอายุย่างเข้ายี่สิบหก ในขณะที่ภาษาซีชาร์พเป็นภาษารุ่นเยาว์ มีอายุเพียงแค่สิบเจ็ดปีเท่านั้น
การที่ซีชาร์พเป็นภาษาน้องใหม่ ภาษานี้จึงได้เปรียบ เพราะมีเทคโนโลยีและแนวคิดในการออกแบบสร้างที่ทันสมัยกว่า
ในบทความนี้ผู้เขียนจะเปรียบเทียบข้อดีแต่ละข้อของภาษาซีชาร์พ กับภาษาอื่น ๆ
โดยจะเลือกเปรียบเทียบกับเฉพาะภาษาที่มีคนนิยมใช้มากที่สุดสามภาษา คือ ซี (รวมถึงซีพลัสพลัส) จาวา และไพธอน
โดยบทความนี้จะแบ่งออกเป็นทั้งหมดหกตอน ในตอนละมีการเปรียบเทียบอยู่สี่หัวข้อ
คอมไพล์เป็นภาษากลาง
คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลาง (Common Intermediate Language (CIL)
ก่อนหน้านี้เรียกว่า Microsoft Intermediate Language (MSIL)) ที่ไม่ผูกกับสถาปัตยกรรมหรือระบบปฏิบัติการ
ในภาษาอื่น ๆ (เช่นภาษาซีและซีพลัสพลัส) เมื่อท่านคอมไพล์โปรแกรม คอมไพล์เลอร์ (Compiler)
จะแปลคำสั่งภาษาซีในซอร์สโค้ดให้กลายเป็นภาษาเครื่อง (Machine Language) ที่มีการทำงานเทียบเท่ากัน
แล้วสร้างเป็นไบนารี่ไฟล์ที่มีนามสกุล .exe (ในระบบปฏิบัติการวินโดวส์) ซึ่งนำไปรันได้เฉพาะในคอมพิวเตอร์ที่มีระบบปฏิบัติการและซีพียูชนิดเดียวกัน
สาเหตุที่โปรแกรมที่คอมไพล์แล้วรันได้เฉพาะระบบปฏิบัติการและซีพียูเนื่องจากซีพียูแต่ละตระกูลหรือยี่ห้อจะมีภาษาเครื่องที่ต่างกัน
ยกตัวอย่างเช่นโปรแกรมที่เขียนและคอมไพล์ในระบบปฏิบัติการวินโดวส์จะรันในระบบปฏิบัติการไลนักซ์ (Linux) ไม่ได้
หรือโปรแกรมที่เขียนและคอมไพล์สำหรับซีพียูตระกูลเพนเทียม จะรันในซีพียูตระกูลอิทาเนียม (Itanium) ไม่ได้
สาเหตุที่ทำให้ภาษาเครื่องและภาษาแอสเซมบลีของซีพียูและจะยี่ห้อแตกต่างกัน อาจมาจากหลายสาเหตุ อาทิ
การที่คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลางมีข้อดีหลายอย่าง อาทิ
- การออกแบบ
ผู้ออกแบบแต่ละคนย่อมกำหนดรหัสของชุดคำสั่งต่าง ๆ (เช่นคำสั่งบวกเลข) ไว้จะแตกต่างกันไป
ตามที่ตนเห็นว่าเหมาะสมโดยไม่มีความจำเป็นหรือคติว่าจะต้องทำให้เข้ากันได้กับใคร
ยกตัวอย่างเช่นในภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์” คำสั่งโหลดตัวเลขเข้ารีจิสเตอร์เอคือโค้ด 03 (ตัวเลขสมมุติ)
แต่ในภาษาแอสเซมบลีของซีพียู “หกห้าศูนย์สอง” คำสั่งโหลดตัวเลขเข้ารีจิสเตอร์เออาจจะเป็นโค้ด 04 (ตัวเลขสมมุติ) ก็ได้
ตามที่ตนเห็นว่าเหมาะสมโดยไม่มีความจำเป็นหรือคติว่าจะต้องทำให้เข้ากันได้กับใคร
ยกตัวอย่างเช่นในภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์” คำสั่งโหลดตัวเลขเข้ารีจิสเตอร์เอคือโค้ด 03 (ตัวเลขสมมุติ)
แต่ในภาษาแอสเซมบลีของซีพียู “หกห้าศูนย์สอง” คำสั่งโหลดตัวเลขเข้ารีจิสเตอร์เออาจจะเป็นโค้ด 04 (ตัวเลขสมมุติ) ก็ได้
- รีจิสเตอร์
ซีพียูทุกยี่ห้อมีรีจิสเตอร์เหมือนกันทั้งนั้น ชั่วแต่จำนวน ชื่อ ขนาด และหน้าที่ของรีจิสเตอร์ในซีพียูแต่ละยี่ห้อจะไม่เหมือนกันเลย
ทำให้โค้ดภาษาเครื่องสำหรับซีพียูแต่ละยี่ห้อไม่อาจใช้งานร่วมกันได้ ยกตัวอย่างเช่นในซีพียู “แซดแปดศูนย์” อาจมีรีจิสเตอร์ “เอช”
ในขณะที่ซีพียู “หกห้าศูนย์สอง” อาจไม่มีรีจิสเตอร์ชื่อเดียวกันนี้อยู่ภายในเลยก็ได้
ทำให้โค้ดภาษาเครื่องสำหรับซีพียูแต่ละยี่ห้อไม่อาจใช้งานร่วมกันได้ ยกตัวอย่างเช่นในซีพียู “แซดแปดศูนย์” อาจมีรีจิสเตอร์ “เอช”
ในขณะที่ซีพียู “หกห้าศูนย์สอง” อาจไม่มีรีจิสเตอร์ชื่อเดียวกันนี้อยู่ภายในเลยก็ได้
- ฮาร์ดแวร์
ซีพียูแต่ละตัวมีฮาร์ดแวร์แตกต่างกัน ซึ่งเป็นปัจจัยที่ทำให้ภาษาเครื่องและภาษาแอสเซมบลี้ของซีพียูแต่ละตัวแตกต่างกันด้วย
ยกตัวอย่างในภาพเป็นซอร์สโค้ดภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์” กับซีพียู “หกห้าศูนย์สอง” เป็นงานลักษณะเดียวกัน
คือเป็นการหน่วงเวลา (ดีเลย์ซับรูทีน) โค้ดต่างกันมากเพราะในโค้ดภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์”
ผู้เขียนใช้วิธีหน่วงเวลาโดยวนการทำงาน ไม่ได้ใช้ฮาร์ดแวร์พิเศษใด ๆ มาร่วมด้วย
ขณะที่โค้ดภาษาแอสเซมบลีของซีพียู “หกห้าศูนย์สอง” ผู้เขียนใช้วิธีหน่วงเวลาด้วยฮาร์ดแวร์พิเศษคือตัวจับเวลา (Timer)
ทำให้ผลลัพธ์เป็นโค้ดภาษาแอสเซมบลีที่นอกจากจะมีรหัสคำสั่งแตกต่างกันแล้ว ยังต่างกันในเทคนิคการเขียนอีกด้วย
ยกตัวอย่างในภาพเป็นซอร์สโค้ดภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์” กับซีพียู “หกห้าศูนย์สอง” เป็นงานลักษณะเดียวกัน
คือเป็นการหน่วงเวลา (ดีเลย์ซับรูทีน) โค้ดต่างกันมากเพราะในโค้ดภาษาแอสเซมบลีของซีพียู “แซดแปดศูนย์”
ผู้เขียนใช้วิธีหน่วงเวลาโดยวนการทำงาน ไม่ได้ใช้ฮาร์ดแวร์พิเศษใด ๆ มาร่วมด้วย
ขณะที่โค้ดภาษาแอสเซมบลีของซีพียู “หกห้าศูนย์สอง” ผู้เขียนใช้วิธีหน่วงเวลาด้วยฮาร์ดแวร์พิเศษคือตัวจับเวลา (Timer)
ทำให้ผลลัพธ์เป็นโค้ดภาษาแอสเซมบลีที่นอกจากจะมีรหัสคำสั่งแตกต่างกันแล้ว ยังต่างกันในเทคนิคการเขียนอีกด้วย
การที่คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลางมีข้อดีหลายอย่าง อาทิ
- ใช้ร่วมกับภาษาอื่นได้
การที่คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลางทำให้เราสามารถใช้งานภาษาซีชาร์พร่วมกับภาษาดอตเน็ตอื่น ๆ ได้
ยกตัวอย่างเช่นเราสามารถเรียกใช้ไลบรารีที่เขียนด้วยภาษาเอฟชาร์พ (ซึ่งคอมไพล์ไว้แล้ว) จากในภาษาซีชาร์พได้โดยตรง ที่ทำอย่างนั้นได้
เพราะภาษาดอตเน็ตทุกภาษาจะถูกคอมไพล์เป็นภาษากลางเหมือนกันทุกภาษา และไม่ต้องกังวลว่าโค้ดต้นทางเป็นแบบ 32 หรือ 64 บิต
เพราะในภาษากลางไม่มีข้อกำหนดความแตกต่างกันระหว่างสถาปัตยกรรมอยู่ภายในเลย
ยกตัวอย่างเช่นเราสามารถเรียกใช้ไลบรารีที่เขียนด้วยภาษาเอฟชาร์พ (ซึ่งคอมไพล์ไว้แล้ว) จากในภาษาซีชาร์พได้โดยตรง ที่ทำอย่างนั้นได้
เพราะภาษาดอตเน็ตทุกภาษาจะถูกคอมไพล์เป็นภาษากลางเหมือนกันทุกภาษา และไม่ต้องกังวลว่าโค้ดต้นทางเป็นแบบ 32 หรือ 64 บิต
เพราะในภาษากลางไม่มีข้อกำหนดความแตกต่างกันระหว่างสถาปัตยกรรมอยู่ภายในเลย
- ปรับแต่งง่าย
การที่คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลางทำให้สามารถปรับแต่งคอมไพล์โค้ดได้ง่าย
ทำให้อาจเพิ่มประสิทธิภาพของคอมไพล์โค้ดเช่นแก้ไขให้ทำงานเร็วขึ้น (ดูภาพที่สอง)
ทำให้อาจเพิ่มประสิทธิภาพของคอมไพล์โค้ดเช่นแก้ไขให้ทำงานเร็วขึ้น (ดูภาพที่สอง)
- เกิดการออพติไมซ์ (optimization) สองระดับ
การที่คอมไพเลอร์ภาษาซีชาร์พแปลซอร์สโค้ดไปเป็นภาษากลางทำให้เกิดการออพติไมซ์สองครั้ง
ครั้งแรกคือตอนคอมไพล์จากซอร์สโค้ดภาษาซีชาร์พไปเป็นภาษากลาง คอมไพเลอร์จะออพติไมซ์ให้คอมไพล์โค้ดภาษากลางมีประสิทธิภาพสูงสุด
และอีกครั้งหนึ่งคือตอนเรียกให้โปรแกรมทำงาน ตัวรันทามน์คอมไพเลอร์ (Just-in-time (JIT))
ซึ่งทำหน้าที่แปลภาษากลาง ให้กลายเป็นภาษาเครื่องอีกทอดหนึ่ง ซึ่งในขั้นตอนนี้ JIT ก็จะออพติไมซ์โค้ดด้วยเช่นกัน
ครั้งแรกคือตอนคอมไพล์จากซอร์สโค้ดภาษาซีชาร์พไปเป็นภาษากลาง คอมไพเลอร์จะออพติไมซ์ให้คอมไพล์โค้ดภาษากลางมีประสิทธิภาพสูงสุด
และอีกครั้งหนึ่งคือตอนเรียกให้โปรแกรมทำงาน ตัวรันทามน์คอมไพเลอร์ (Just-in-time (JIT))
ซึ่งทำหน้าที่แปลภาษากลาง ให้กลายเป็นภาษาเครื่องอีกทอดหนึ่ง ซึ่งในขั้นตอนนี้ JIT ก็จะออพติไมซ์โค้ดด้วยเช่นกัน
บรรทัดที่ 1-4 คือซอร์สโค้ดภาษาซีชาร์ฟ บรรทัดที่ 6-17 เป็นผลลัพธ์จากการคอมไพล์ให้เป็นภาษากลาง
บรรทัดที่ 19-28 คือผลลัพธ์จากการปรับแต่งโค้ดภาษากลางให้สั้นลงและทำงานได้เร็วขึ้นด้วยมือ
กำจัดขยะโดยอัตโนมัติ
ภาษาซีชาร์พมีกลไกชื่อ “ตัวเก็บขยะอัตโนมัติ” (Automatic garbage collection)
ช่วยแก้ปัญหา “การไม่คืนหน่วยความจำ” (Memory Leak) ซึ่งเป็นบักที่พบได้บ่อยในภาษาอื่น ๆ เช่นภาษาซี
ปัญหา “การไม่คืนหน่วยความจำ” เกิดจากความสะเพร่าของผู้เขียนโปรแกรมที่จองหน่วยความจำเพื่อใช้งาน
และต่อมาภายหลังเมื่อใช้งานหน่วยความจำนั้นเสร็จแล้วลืมคืน (คือลืมให้โปรแกรมวิ่งไปทำงานโค้ดส่วนที่คืนหน่วยความจำ)
มีผลให้การจองหน่วยความจำค้างเติ่งอยู่ และจะมีผลเช่นนั้นตลอดไป บ่อยครั้งที่การจองเกิดซ้ำอีกอย่างถี่ ๆ
ซึ่งจะมีผลให้หน่วยความจำของระบบลดลงอย่างรวดเร็ว ในกรณีดีที่สุดคือเครื่องทำงานอย่างมีประสิทธิภาพลดลง
ในกรณีที่เลวสุดคือเครื่องค้างและหยุดการทำงานไปเลย
บรรทัดที่ 19-28 คือผลลัพธ์จากการปรับแต่งโค้ดภาษากลางให้สั้นลงและทำงานได้เร็วขึ้นด้วยมือ
กำจัดขยะโดยอัตโนมัติ
ภาษาซีชาร์พมีกลไกชื่อ “ตัวเก็บขยะอัตโนมัติ” (Automatic garbage collection)
ช่วยแก้ปัญหา “การไม่คืนหน่วยความจำ” (Memory Leak) ซึ่งเป็นบักที่พบได้บ่อยในภาษาอื่น ๆ เช่นภาษาซี
ปัญหา “การไม่คืนหน่วยความจำ” เกิดจากความสะเพร่าของผู้เขียนโปรแกรมที่จองหน่วยความจำเพื่อใช้งาน
และต่อมาภายหลังเมื่อใช้งานหน่วยความจำนั้นเสร็จแล้วลืมคืน (คือลืมให้โปรแกรมวิ่งไปทำงานโค้ดส่วนที่คืนหน่วยความจำ)
มีผลให้การจองหน่วยความจำค้างเติ่งอยู่ และจะมีผลเช่นนั้นตลอดไป บ่อยครั้งที่การจองเกิดซ้ำอีกอย่างถี่ ๆ
ซึ่งจะมีผลให้หน่วยความจำของระบบลดลงอย่างรวดเร็ว ในกรณีดีที่สุดคือเครื่องทำงานอย่างมีประสิทธิภาพลดลง
ในกรณีที่เลวสุดคือเครื่องค้างและหยุดการทำงานไปเลย
โค้ดตัวอย่างแสดงเหตุการ “ไม่คืนหน่วยความจำ” ในภาษาซีพลัสพลัส
โค้ดบรรทัดที่ 23 แสดงการสร้างออพเจ็กต์ p หนึ่งออพเจ็กต์ที่จะจองหน่วยความจำเพื่อใช้เก็บข้อมูลของออพเจ็กต์
โค้ดบรรทัดที่ 24 มีคำสั่งลบออพเจ็กต์ซึ่งจะทำหน้าที่คืนหน่วยความจำที่จองไว้สำหรับออพเจ็กต์นี้ นี่คือตัวอย่างกรณีไม่มีปัญหา “การไม่คืนหน่วยความจำ”
โค้ดบรรทัดที่ 27 มีการ new ออพเจ็กต์แต่หลังจากนั้นไม่ได้ delete จะมีผลให้การจองหน่วยความจำสำหรับออพเจ็กต์นั้นยังคงค้างอยู่ไปตลอด
ในกรณีที่เป็น “การไม่คืนหน่วยความจำ” ของออพเจ็กต์เพียงตัวเดียวจะไม่มีปัญหามากนัก
เพราะออพเจ็กต์ตัวเดียวใช้หน่วยความจำไม่มาก แต่ถ้าเป็นออพเจ็กต์จำนวนมากจะมีปัญหาทันที
ยกตัวอย่างเช่น โค้ดบรรทัดที่ 30 เรียกฟังก์ชัน create_list() ซึ่งทำหน้าที่สร้างออพเจ็กต์จำนวน 2,147,483,647 ตัว
ถ้าผู้เขียนโปรแกรมลืมใส่โค้ดเรียกฟังก์ชัน destroy_list() เพื่อทำลายออพเจ็กต์จะเกิด “การไม่คืนหน่วยความจำ” ของหน่วยความจำจำนวนมากซึ่งนับว่าเป็นบักร้ายแรงชนิดหนึ่ง
ในกรณีที่เป็นภาษาซีชาร์พ ปัญหานี้ถูกตัดออกไปได้ เพราะตัวรันทามน์ (Common Language Runtime (CLR)) จะคอยเฝ้าติดตามการสร้างและใช้งานออพเจ็กต์อยู่เสมอ
เมื่อพบว่าออพเจ็กต์ใด้ไม่เป็นที่ต้องการแล้ว CLR จะนำออพเจ็กต์นั้นเข้าสู่กระบวนการเตรียมทำลายให้เองโดยอัตโนมัติ
โปรแกรมเมอร์ไม่จำเป็นต้องเขียนโค้ดและสั่งให้ทำลายออพเจ็กต์ด้วยตนเอง จึงมีผลให้เอพลิเกชันที่ถูกพัฒนาด้วยภาษาซีชาร์พมีความปลอดภัยและมีสเถียรภาพสูงกว่า
ไม่จำเป็นต้องใช้พอยน์เตอร์
การเขียนโปรแกรมในภาษาซีชาร์พ เราไม่จำเป็นต้องใช้พอยน์เตอร์ซึ่งมีข้อดีที่ทำให้แอพลิเกชันมีความปลอดภัยและมีสเถียรภาพสูง
หัวใจของภาษาซี คือ พอยน์เตอร์ โปรแกรมเมอร์ภาษาซีจะใช้พอยน์เตอร์เป็นเครื่องมือหลักในการทำสิ่งต่าง ๆ เพราะพอยน์เตอร์ช่วยให้การเข้าถึงหน่วยความจำส่วนใด ๆ เป็นไปได้อย่างสะดวกรวดเร็ว
แต่ข้อเสียของการใช้พอยน์เตอร์ คือ หากผู้เขียนโค้ดสะเพร่าอาจจะเขียนข้อมูลไปยังหน่วยความจำผิดตำแหน่ง
ในกรณีดีสุดคือโปรแกรมทำงานผิดพลาดไปอย่างเงียบ ๆ
กรณีเลวสุดคือเครื่องค้างและหยุดการทำงานไปเลยเพราะเขียนข้อมูลไปยังหน่วยความจำบริเวณต้องห้ามของระบบปฏิบัติการ
เพื่อให้เอพลิเกชันที่ถูกพัฒนาด้วยภาษาซีชาร์พ มีความปลอดภัยและมีสเถียรภาพสูง
ภาษาซีชาร์พจึงไม่เน้นการใช้พอยน์ตอร์
ท่านจะสามารถอ้างถึงออพเจ็กต์และทำทุกสิ่งทุกอย่างได้โดยไม่ต้องยุ่งเกี่ยวกับพอยน์เตอร์เลย
ท่านอาจประกาศและใช้งานพอยน์เตอร์ในภาษาซีชาร์พก็ได้
แต่จะต้องประกาศให้ตัวแปลภาษารู้ว่าโค้ดก้อนนั้นเป็นโค้ดที่ไม่ปลอดภัย (unsafe code block)
โค้ดบรรทัดที่ 23 แสดงการสร้างออพเจ็กต์ p หนึ่งออพเจ็กต์ที่จะจองหน่วยความจำเพื่อใช้เก็บข้อมูลของออพเจ็กต์
โค้ดบรรทัดที่ 24 มีคำสั่งลบออพเจ็กต์ซึ่งจะทำหน้าที่คืนหน่วยความจำที่จองไว้สำหรับออพเจ็กต์นี้ นี่คือตัวอย่างกรณีไม่มีปัญหา “การไม่คืนหน่วยความจำ”
โค้ดบรรทัดที่ 27 มีการ new ออพเจ็กต์แต่หลังจากนั้นไม่ได้ delete จะมีผลให้การจองหน่วยความจำสำหรับออพเจ็กต์นั้นยังคงค้างอยู่ไปตลอด
ในกรณีที่เป็น “การไม่คืนหน่วยความจำ” ของออพเจ็กต์เพียงตัวเดียวจะไม่มีปัญหามากนัก
เพราะออพเจ็กต์ตัวเดียวใช้หน่วยความจำไม่มาก แต่ถ้าเป็นออพเจ็กต์จำนวนมากจะมีปัญหาทันที
ยกตัวอย่างเช่น โค้ดบรรทัดที่ 30 เรียกฟังก์ชัน create_list() ซึ่งทำหน้าที่สร้างออพเจ็กต์จำนวน 2,147,483,647 ตัว
ถ้าผู้เขียนโปรแกรมลืมใส่โค้ดเรียกฟังก์ชัน destroy_list() เพื่อทำลายออพเจ็กต์จะเกิด “การไม่คืนหน่วยความจำ” ของหน่วยความจำจำนวนมากซึ่งนับว่าเป็นบักร้ายแรงชนิดหนึ่ง
ในกรณีที่เป็นภาษาซีชาร์พ ปัญหานี้ถูกตัดออกไปได้ เพราะตัวรันทามน์ (Common Language Runtime (CLR)) จะคอยเฝ้าติดตามการสร้างและใช้งานออพเจ็กต์อยู่เสมอ
เมื่อพบว่าออพเจ็กต์ใด้ไม่เป็นที่ต้องการแล้ว CLR จะนำออพเจ็กต์นั้นเข้าสู่กระบวนการเตรียมทำลายให้เองโดยอัตโนมัติ
โปรแกรมเมอร์ไม่จำเป็นต้องเขียนโค้ดและสั่งให้ทำลายออพเจ็กต์ด้วยตนเอง จึงมีผลให้เอพลิเกชันที่ถูกพัฒนาด้วยภาษาซีชาร์พมีความปลอดภัยและมีสเถียรภาพสูงกว่า
ไม่จำเป็นต้องใช้พอยน์เตอร์
การเขียนโปรแกรมในภาษาซีชาร์พ เราไม่จำเป็นต้องใช้พอยน์เตอร์ซึ่งมีข้อดีที่ทำให้แอพลิเกชันมีความปลอดภัยและมีสเถียรภาพสูง
หัวใจของภาษาซี คือ พอยน์เตอร์ โปรแกรมเมอร์ภาษาซีจะใช้พอยน์เตอร์เป็นเครื่องมือหลักในการทำสิ่งต่าง ๆ เพราะพอยน์เตอร์ช่วยให้การเข้าถึงหน่วยความจำส่วนใด ๆ เป็นไปได้อย่างสะดวกรวดเร็ว
แต่ข้อเสียของการใช้พอยน์เตอร์ คือ หากผู้เขียนโค้ดสะเพร่าอาจจะเขียนข้อมูลไปยังหน่วยความจำผิดตำแหน่ง
ในกรณีดีสุดคือโปรแกรมทำงานผิดพลาดไปอย่างเงียบ ๆ
กรณีเลวสุดคือเครื่องค้างและหยุดการทำงานไปเลยเพราะเขียนข้อมูลไปยังหน่วยความจำบริเวณต้องห้ามของระบบปฏิบัติการ
เพื่อให้เอพลิเกชันที่ถูกพัฒนาด้วยภาษาซีชาร์พ มีความปลอดภัยและมีสเถียรภาพสูง
ภาษาซีชาร์พจึงไม่เน้นการใช้พอยน์ตอร์
ท่านจะสามารถอ้างถึงออพเจ็กต์และทำทุกสิ่งทุกอย่างได้โดยไม่ต้องยุ่งเกี่ยวกับพอยน์เตอร์เลย
ท่านอาจประกาศและใช้งานพอยน์เตอร์ในภาษาซีชาร์พก็ได้
แต่จะต้องประกาศให้ตัวแปลภาษารู้ว่าโค้ดก้อนนั้นเป็นโค้ดที่ไม่ปลอดภัย (unsafe code block)
เปรียบเทียบโค้ดภาษาซีพลัสพลัสที่อ้างถึงออพเจ็กต์โดยใช้พอยน์เตอร์กับโค้ดภาษาซีชาร์พที่ไม่ใช้พอยน์เตอร์แต่อ้างถึงออพเจ็กต์โดยตรง
โค้ดบรรทัดที่ 1 ถึง 9 คือโค้ดภาษาซีพลัสพลัส
โค้ดบรรทัดที่ 2 ถึง 4 คือนิยามฟังก์ชัน f ดูบรรทัดที่ 2 จะเห็นว่าฟังก์ชันนี้มีพารามิเตอร์หนึ่งตัว (* p) ซึ่งมีชนิดเป็นออพเจ็กต์พอยน์เตอร์
โค้ดบรรทัดที่ 3 เรียกหาฟังก์ชัน DoSomething() ซึ่งเป็นฟังก์ชันที่อยู่ภายในคลาส MyClass
โค้ดบรรทัดที่ 6 ถึง 9 คือฟังก์ชัน main
โค้ดบรรทัด 7 ประกาศตัวแปร c ที่มีไทป์ (data type) เป็น MyClass
โค้ดบรรทัด 8 เรียกฟังก์ชัน f โดยส่งแอดเดรสของตัวแปร c ไปเป็นอาร์กิวเมนต์
โค้ดบรรทัดที่ 14 ถึง 21 เป็นโค้ดภาษาซีชาร์พ ในบรรทัด 14 จะเห็นว่าเรากำหนดพารามิเตอร์เป็นตัวแปรที่มีไทป์เป็นคลาส MyClass ได้โดยตรง ไม่จำเป็นต้องใช้พอยน์เตอร์
โค้ดบรรทัด 19 ประกาศตัวแปร c และใช้ตัวกระทำ new เพื่อสร้างออพเจ็กต์และส่งออพเจ็กต์นี้ไปเป็นอาร์กิวเมนต์ของการเรียกฟังก์ชัน f ในโค้ดบรรทัด 20 ได้โดยตรง ไม่จำเป็นต้องอ้างถึงแอดเดรสอย่างในภาษาซีพลัสพลัส
สนับสนุนรีเฟล็กซ์ชัน
การที่ภาษาซีชาร์พสนับสนุนรีเฟล็กซ์ชัน (Reflection) ทำให้การเขียนโปรแกรมทำได้ง่ายขึ้นเพราะเราสามารถอ่านข้อมูลเมต้าดาต้า (meta data) ในแอสเซมบลี (assembly)
ซึ่งช่วยให้เราสามารถทำบางอย่างที่การเขียนโปรแกรมตามปรกติโดยไม่ได้ใช้รีเฟล็กซ์ชันไม่สามารถทำได้หรือทำได้ลำบาก
ยกตัวอย่างเช่น การตรวจสอบว่าภายในแอสเซมบลีมีโมดูลอะไรอยู่บ้าง ในแต่ละโมดูลมีไทป์อะไรอยู่ภายในบ้าง
และในแต่ละไทป์มีสมาชิกอะไรอยู่ภายในบ้าง ใช้เพื่อผูกไทป์กับออพเจ็กต์ที่มีอยู่แล้วเป็นต้น
รีเฟล็กซ์ชันคล้าย ๆ คุณสมบัติ “การดูข้อมูลของไทป์ตอนรัน” (Runtime Type Information (RTTI)) ในภาษาซีพลัสพลัส
แต่ก้าวหน้ากว่าและมีความสามารถสูงกว่า
ยกตัวอย่างเช่น เราสามารถใช้รีเฟล็กซ์ชันเพื่อดูรายการแอตทริบิวต์ (attribute) เรียกใช้งานออพเจ็กต์ อ่านหรือเขียนค่าของสมาชิกแบบฟิลด์ของออพเจ็กต์เป็นต้น
โค้ดบรรทัดที่ 1 ถึง 9 คือโค้ดภาษาซีพลัสพลัส
โค้ดบรรทัดที่ 2 ถึง 4 คือนิยามฟังก์ชัน f ดูบรรทัดที่ 2 จะเห็นว่าฟังก์ชันนี้มีพารามิเตอร์หนึ่งตัว (* p) ซึ่งมีชนิดเป็นออพเจ็กต์พอยน์เตอร์
โค้ดบรรทัดที่ 3 เรียกหาฟังก์ชัน DoSomething() ซึ่งเป็นฟังก์ชันที่อยู่ภายในคลาส MyClass
โค้ดบรรทัดที่ 6 ถึง 9 คือฟังก์ชัน main
โค้ดบรรทัด 7 ประกาศตัวแปร c ที่มีไทป์ (data type) เป็น MyClass
โค้ดบรรทัด 8 เรียกฟังก์ชัน f โดยส่งแอดเดรสของตัวแปร c ไปเป็นอาร์กิวเมนต์
โค้ดบรรทัดที่ 14 ถึง 21 เป็นโค้ดภาษาซีชาร์พ ในบรรทัด 14 จะเห็นว่าเรากำหนดพารามิเตอร์เป็นตัวแปรที่มีไทป์เป็นคลาส MyClass ได้โดยตรง ไม่จำเป็นต้องใช้พอยน์เตอร์
โค้ดบรรทัด 19 ประกาศตัวแปร c และใช้ตัวกระทำ new เพื่อสร้างออพเจ็กต์และส่งออพเจ็กต์นี้ไปเป็นอาร์กิวเมนต์ของการเรียกฟังก์ชัน f ในโค้ดบรรทัด 20 ได้โดยตรง ไม่จำเป็นต้องอ้างถึงแอดเดรสอย่างในภาษาซีพลัสพลัส
สนับสนุนรีเฟล็กซ์ชัน
การที่ภาษาซีชาร์พสนับสนุนรีเฟล็กซ์ชัน (Reflection) ทำให้การเขียนโปรแกรมทำได้ง่ายขึ้นเพราะเราสามารถอ่านข้อมูลเมต้าดาต้า (meta data) ในแอสเซมบลี (assembly)
ซึ่งช่วยให้เราสามารถทำบางอย่างที่การเขียนโปรแกรมตามปรกติโดยไม่ได้ใช้รีเฟล็กซ์ชันไม่สามารถทำได้หรือทำได้ลำบาก
ยกตัวอย่างเช่น การตรวจสอบว่าภายในแอสเซมบลีมีโมดูลอะไรอยู่บ้าง ในแต่ละโมดูลมีไทป์อะไรอยู่ภายในบ้าง
และในแต่ละไทป์มีสมาชิกอะไรอยู่ภายในบ้าง ใช้เพื่อผูกไทป์กับออพเจ็กต์ที่มีอยู่แล้วเป็นต้น
รีเฟล็กซ์ชันคล้าย ๆ คุณสมบัติ “การดูข้อมูลของไทป์ตอนรัน” (Runtime Type Information (RTTI)) ในภาษาซีพลัสพลัส
แต่ก้าวหน้ากว่าและมีความสามารถสูงกว่า
ยกตัวอย่างเช่น เราสามารถใช้รีเฟล็กซ์ชันเพื่อดูรายการแอตทริบิวต์ (attribute) เรียกใช้งานออพเจ็กต์ อ่านหรือเขียนค่าของสมาชิกแบบฟิลด์ของออพเจ็กต์เป็นต้น
นี่คือโค้ดภาษาซีชาร์พ แสดงตัวอย่างการทำรีเฟล็กซ์ชัน
บรรทัดที่ 4 ถึง 6 แสดงการใช้รีเฟล็กซ์ชันเพื่อหาไทป์ของออพเจ็กต์ ในกรณีนี้เราเพียงแค่เรียกใช้เมธอด GetType()
ซึ่งทุกออพเจ็กต์มีออพเจ็กต์นี้เพราะล้วนสืบคุณสมบัติมาจากออพเจ็กต์ต้นตระกูลที่มีนิยามเมธอดนี้ และในภาษาซีชาร์พทุกอย่างเป็นออพเจ็กต์ ไม่เว้นแม้แต่ตัวแปร
ด้วยเหตุนี้เราจึงสามารถเรียกหาเมธอด GetType() จากตัวแปร i ได้ด้วย ผลลัพธ์ของการทำงานจึงเป็นอย่างที่เห็นในบรรทัดที่ 7
ตัวอย่างที่สอง
บรรทัดที่ 10, 11 แสดงการใช้รีเฟล็กซ์ชันเพื่อหาข้อมูลของตัวแอสเซมบลี
ในตัวอย่างนี้ใช้ไทป์ Assembly ที่อยู่ในเนมสเปส System.Reflection ผลของการทำงานเป็นอย่างที่เห็นในบรรทัดที่ 13
ตัวอย่างที่สาม
บรรทัดที่ 17, 19 แสดงการใช้รีเฟล็กซ์ชันเพื่อสร้างอินสแตนซ์ของคลาส (สร้างออพเจ็กต์)
ยกตัวอย่างเช่นปรกติเมื่อเราต้องการสร้างออพเจ็กต์ที่มีไทป์ DateTime เราจะเขียนโค้ดแบบบรรทัดที่ 17
แต่ถ้าเราต้องการทำโดยใช้ รีเฟล็กซ์ชัน โค้ดจะเป็นอย่างที่เห็นในบรรทัดที่ 19
บรรทัดที่ 4 ถึง 6 แสดงการใช้รีเฟล็กซ์ชันเพื่อหาไทป์ของออพเจ็กต์ ในกรณีนี้เราเพียงแค่เรียกใช้เมธอด GetType()
ซึ่งทุกออพเจ็กต์มีออพเจ็กต์นี้เพราะล้วนสืบคุณสมบัติมาจากออพเจ็กต์ต้นตระกูลที่มีนิยามเมธอดนี้ และในภาษาซีชาร์พทุกอย่างเป็นออพเจ็กต์ ไม่เว้นแม้แต่ตัวแปร
ด้วยเหตุนี้เราจึงสามารถเรียกหาเมธอด GetType() จากตัวแปร i ได้ด้วย ผลลัพธ์ของการทำงานจึงเป็นอย่างที่เห็นในบรรทัดที่ 7
ตัวอย่างที่สอง
บรรทัดที่ 10, 11 แสดงการใช้รีเฟล็กซ์ชันเพื่อหาข้อมูลของตัวแอสเซมบลี
ในตัวอย่างนี้ใช้ไทป์ Assembly ที่อยู่ในเนมสเปส System.Reflection ผลของการทำงานเป็นอย่างที่เห็นในบรรทัดที่ 13
ตัวอย่างที่สาม
บรรทัดที่ 17, 19 แสดงการใช้รีเฟล็กซ์ชันเพื่อสร้างอินสแตนซ์ของคลาส (สร้างออพเจ็กต์)
ยกตัวอย่างเช่นปรกติเมื่อเราต้องการสร้างออพเจ็กต์ที่มีไทป์ DateTime เราจะเขียนโค้ดแบบบรรทัดที่ 17
แต่ถ้าเราต้องการทำโดยใช้ รีเฟล็กซ์ชัน โค้ดจะเป็นอย่างที่เห็นในบรรทัดที่ 19