ตอน 15 : Reference type


ไปหน้าแรก | สารบัญ | Laploy.comระเบียนบทความ | บทความจากลาภลอย

เว็บไซต์นี้เป็นตัวอย่างเนื้อหาบางตอนในหนังสือ "เรียนรู้ด้วยตนเอง OOP C# ASP.NET" ครอบคลุม บทที่ 1 ถึงบทที่ 6 (ในหนังสือมี 21 บท) เนื้อหาใน Blog อาจอาจแตกต่างจากในหนังสือเพราะเป็นเนื้อหาที่ยังไม่ได้ตรวจแก้ขัดเกลา (edit)

กดที่นี่เพื่อดูรายละเอียดเนื้อหาในแต่ละบท

กดที่นี่เพื่อไปยังเว็บบอร์ด ถาม-ตอบ 

 

 

Reference type

 

ภาษา C# ก็เช่นเดียวกับภาษา Java C++ และภาษาแบบ OOP อื่นๆ ที่มีการใช้ตัวแปรแบบ reference type อย่างกว้างขวาง การทำความเข้าใจเรื่อง reference type จึงมีความสำคัญมาก ดังนั้นโปรดอ่านเรื่องในหัวข้อนี้อย่างมีสมาธิ เริ่มจากการดูตัวอย่างโค้ดสองบรรทัดนี้

 

StringBuilder foo = new StringBuilder();

foo.Append("hello");

 

โค้ดบรรทัดแรกสร้างตัวแปรชื่อ foo ซึ่งเป็นตัวแปรแบบ reference type คำว่า StringBuilder เป็นชื่อคลาสๆ หนึ่งใน .NET Framework ทำหน้าที่จัดการข้อความตัวอักษร ผู้เขียนยกตัวอย่างคลาสนี้โดยการสุ่มเลือก มันไม่มีข้อดีวิเศษจำเพาะเจาะจงอะไร หากเรากำหนดให้ตัวแปรมี type เป็นคลาส ไม่ว่าจะเป็นคลาสไหนก็ตาม ตัวแปรตัวนั้นจะกลายเป็น reference type ไปทั้งนั้น (บางคนเรียกตัวแปรวัตถุ)

คำสั่งบรรทัดที่สองทำหน้าที่นำข้อความ hello ไปเก็บในที่เก็บข้อมูลของ object ตัวนี้ เมื่อโปรแกรมบรรทัดแรกทำงาน CLR จะสร้างกล่องในหน่วยความจำสองใบ ใบแรกสร้างไว้ใน heap ทำหน้าที่เก็บข้อมูลของ object ที่ถูกสร้างจากคลาส StringBuilder กล่องนี้เป็นกล่องที่ไม่มีชื่อ อีกกล่องหนึ่งถูกสร้างไว้ใน stack กล่องนี้มีชื่อว่า foo ทำหน้าที่เก็บค่าอ้างอิงไปยังกล่องใบแรก ท่านคิดว่าข้อความ hello ที่เราใส่ไว้ใน object ถูกนำไปเก็บไว้ในกล่องใบไหน?

 

คำตอบคือกล่องใบแรก (ใน heap)

 

ถ้าท่านอ่านแล้วยังไม่เข้าใจว่า hello ไปอยู่ในกล่องใบแรกได้อย่างไรให้ดูภาพ 307

 

ภาพ 307: การสร้าง object จากคลาส StringBuilder

 

ในไลบรารีของ .NET (1) มีคลาสชื่อ StringBuilder (2) คำสั่งบรรทัดแรกสร้างตัวแปรชื่อ foo จากคลาส StringBuilder (6) ทำให้เราได้พื้นที่เก็บข้อมูลภายใน stack (7-8) คำสั่ง new StringBuilder (3) ทำหน้าที่สร้างอินสแตนซ์ ของคลาส (4) ทำให้เราได้พื้นที่เก็บข้อมูลใน heap (5) ตัวแปร foo ทำหน้าที่เก็บค่าอ้างอิง (9) ไปยัง object ค่านี้ก็คือค่าตำแหน่งใน heap ของ object นั่นเอง เมื่อเราต้องการทำงานกับ object ตัวนี้เราก็ติดต่อมันผ่านตัวแปร foo ดังนั้นตัวแปร foo จึงทำหน้าที่เป็นตัวกลางระหว่างเรากับ object เมื่อเราต้องการอ้างถึงข้อมูลใน object เราก็อ้างถึงผ่านตัวแปร foo

การทำเช่นนี้เป็นการเข้าถึงข้อมูลโดยทางอ้อม (เหมือน Indirect addressing mode ในภาษาแอสเซมบลี) เราจึงกล่าวได้ว่า foo เป็นตัวแปรที่มี type เป็น reference type หากท่านอ่านสองหัวข้อนี้แล้วยังไม่เข้าใจเรื่อง value และ reference type โปรดทบทวนเรื่อง CLR, heap, stack ในบทที่ 2 และโปรดดูตัวอย่างการประยุกต์ใช้ พร้อมคำอธิบายการใช้งานจริงๆ ในบทที่ 14

 

การทำ Boxing และ Unboxing

บางครั้งเราจำเป็นต้องแปลงตัวแปรที่เป็น value type ให้กลายเป็น reference type (หรือลับกัน) ภาษา C# มีกลไกลให้ทำได้ง่ายๆ เรียกว่า boxing (อ่านว่าบ็อกซิง) และ unboxing (อ่านว่าอันบ็อกซิง)

boxing คือการแปลง value type เป็น reference type (ซึ่งจะถูกนำไปใส่ไว้ใน heap) ส่วน unboxing คือการแปลง reference type ให้เป็น value type (ซึ่งจะถูกนำไปใส่ใน stack) ลองดูตัวอย่างโค้ดต่อไปนี้

 

int foo1 = 123;

object foo2 = (object)foo1;

 

โค้ดสองบรรทัดนี้คือตัวอย่างการทำ boxing หรือการเปลี่ยน value type ให้เป็น reference type บรรทัดบนทำหน้าที่สร้างตัวแปรแบบ int ชื่อ foo1 ซึ่งเป็น value type บรรทัดล่างคือการ boxing โดยสร้างตัวแปร foo2 ซึ่งมี type เป็น object ให้อ้างไปยัง foo1

ต่อไปเป็นตัวอย่างการทำ unboxing

 

foo2 = 123;

foo1 = (int)foo2;

 

โค้ดสองบรรทัดนี้สาทิตการทำ unboxing หรือการเปลี่ยน reference type ให้กลายเป็น value type บรรทัดบนเรามี object ชื่อ foo2 (เป็น object ที่ได้จากตัวอย่างก่อนหน้านี้) บรรทัดล่างคือการ unboxing โดยเปลี่ยน object ที่ foo2 อ้างถึงอยู่ให้กลายเป็น int แล้วกำหนดให้ foo1 อ้างถึงสิ่งนั้น

แนวคิดการทำ boxing และ unboxing ไม่ได้มีอยู่เฉพาะภาษา C# เท่านั้น แต่มันเป็นส่วนหนึ่งของ .NET เอง นักเขียนโปรแกรมหลายคนตั้งคำถามว่า “ในเมื่อไมโครซอฟท์ย้ำนักย้ำหนาว่าทุกอย่างใน C# เป็น object ทั้งหมด เหตุใดจึงยังมีการทำ boxing และ unboxing” คำตอบคือ primitive type อย่าง int แม้จะมีต้นกำเนิดจากคลาส (คือ System.Int32) แต่มันถูกทำให้เป็น value type (ซึ่งมีภูมิลำเนาใน stack ) เพื่อเพิ่มประสิทธิภาพของโปรแกรม

 

ตอนต่อไป: Class

Post a comment or leave a trackback: Trackback URL.

ความเห็น

  • Chomphun  On มกราคม 10, 2008 at 4:46 pm

    อ่านแล้วเข้าใจอะไรได้เยอะเลยค่ะ ขอบคุณค่ะ

  • Akarat  On ตุลาคม 1, 2009 at 12:30 pm

    GEt มากมาย thanks ครับ

ส่งความเห็นที่ Chomphun ยกเลิกการตอบ