Monthly Archives: พฤศจิกายน 2006

ตอน 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

Advertisements

ตอน 14 : โปรแกรม Hello world

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


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

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

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

 

 

โปรแกรม Hello world

 

ข้างล่างนี้คือโค้ดภาษา C# ที่สั้นที่สุด ทำหน้าที่พิมพ์คำว่า Hello world บนจอภาพ

 

using System;

public class Hello
{
     static void Main()
     {
          Console.WriteLine("Hello world");
     }
}

 

นี่เป็นโปรแกรมแบบ Console application คือไม่มีกรอบวินโดว์ (WinForm) แต่จะแสดงการทำงานเลียนแบบเท็กซ์โหมดเหมือนโปรแกรมใน MS-DOS

using System;

บรรทัดแรกทำหน้าที่บอกให้ตัวแปลภาษา (compiler) นำ name space ชื่อ System ซึ่งอยู่ใน .NET Framework Class library มารวมไว้ใน name space ของคลาสนี้ด้วย

public class Hello

บรรทัดนี้ทำหน้าที่ประกาศชื่อคลาส คำว่า public ทำหน้าที่กำหนดว่าคลาสนี้ใครก็นำไปใช้งานได้

static void Main()

บรรทัดนี้ทำหน้าที่ประกาศชื่อ method ซึ่งเป็นสมาชิกของคลาส Hello method ชื่อ Main() เป็น method พิเศษซึ่งจะเริ่มทำงานก่อนโดยอัตโนมัติเมื่อเราสั่งให้โปรแกรมทำงาน คำว่า static เป็น keyword ทำหน้าที่บอกว่า method นี้เป็น method ของ type นี้ มิได้เป็น method ของ object

Console.WriteLine("Hello world");

คำสั่งบรรทัดนี้ทำหน้าที่แสดงข้อความ Hello world บนจอภาพโดยเรียกใช้ method WriteLine ซึ่งเป็น method สมาชิกของคลาส Console

 

โครงสร้างของโปรแกรมในภาษา C#

source code ภาษา C# จะถูกเก็บเป็นไฟล์นามสกุล .cs ซึ่งเป็นเท็กซ์ไฟล์ธรรมดา (plain text file) สามารถสร้างจาก text editor อะไรก็ได้ แต่โดยปรกติและเราจะใช้เครื่องมืออำนวยความสะดวก เป็นภาพแวดล้อมที่ช่วยให้พัฒนาได้ง่ายขึ้น (หรือ IDE ย่อจาก Integrated Development Environment) เช่น Visual Studio ของบริษัทไมโครซอฟท์

หากท่านยังไม่ต้องการเสียเงินซื้อ Visual Studio แต่ต้องการ IDE ดีๆ สำหรับการเรียนรู้ บริษัทไมโครซอฟท์มี Visual Studio แบบที่ให้ใช้ได้ฟรีเรียกว่า Express Edition ซึ่งมีประสิทธิภาพใกล้เคียงกับเวอร์ชันปรกติให้ดาวน์โหลดใช้ได้ฟรี โดยแบ่งออกเป็นแบบรวมทุกภาษา และแยกตามภาษาต่างๆ ให้เลือกตามความต้องการ สำหรับผู้ต้องการเขียน web application ก็มี Visual Web Developer 2005 Express Edition ให้ดาวน์โหลดได้ฟรีเช่นกัน

source code ภาษา C# อาจจะประกอบด้วยไฟล์ .cs เพียงไฟล์เดียว แต่ตามปรกติแล้วภายในหนึ่ง project จะประกอบด้วยไฟล์ .cs และไฟล์ชนิดอื่นๆ เป็นจำนวนมาก source code ทั้หงมดอาจจะเป็น name space เดียวกันหรือแยกเป็นหลาย name space ก็ได้ ภายในหนึ่ง name space มักประกอบด้วย คลาส struct, interface, delegate และ enum จำนวนมาก (ดูภาพ 302)

ภาพ 302: โครงสร้างของโปรแกรมในภาษา C#

 

ในกรณีที่เราสร้างโปรแกรมประยุกต์สำหรับใช้งานในเว็บ (Web application software development) จะมีไฟล์ “หน้าเว็บ” (WebForm) เพิ่มขึ้นมาด้วยคู่กับทุก .cs ไฟล์ โดยจะมีนามสกุล .aspx การที่ผู้สร้าง .NET ทำเช่นนี้ก็เพื่อที่จะแยกส่วนแสดงผล (presentation คือไฟล์ .aspx ซึ่งเก็บโค้ด html) ออกจากส่วนประมวลผล (ไฟล์ source code ภาษา C# คือไฟล์นามสกุล .cs) การแบ่งเป็นสองไฟล์เช่นนี้ ช่วยผลกระทบระหว่างกันในกรณีแบ่งงานกันทำระหว่างนักออกแบบทางศิลปะและโปรแกรมเมอร์ (หลักการนี้มักเรียกกว่า code behind)

 

namespace

เพื่อหลีกเลี่ยงการตั้งชื่อ type ซ้ำกันและเพื่อการจัดหมวดหมู่ type ในกลุ่มเดียวกันไว้ด้วยกัน Microsoft .NET Framework (MNF) จึงจัดให้มีระบบที่เรียกว่า Namespace ขึ้น ลองดูตัวอย่างโค้ดต่อไปนี้

 

namespace CsharpBook.Chapter04
{
     class Foo
     {
          public Foo()
          {
               int i;
               Foo f2;
          }
     }
}

 

ผู้เขียนนิยาม namespace ชื่อ CsharpBook.Chapter04 ขึ้น ภายใน Namespace นี้มีคลาสชื่อ Foo อยู่เพียงคลาสเดียว การอ้างถึง type Foo หากอ้างถึงโดยใช้ชื่อเต็ม (fully-qualified class name หรือ FQCN) จะเป็น CsharpBook.Chapter04.Foo

หากผู้เขียนนำโค้ดนี้ไปคอมไพล์ให้เป็นไลบราลี จะได้เป็นไฟล์ assembly แบบ .dll ชื่อ CsharpBook.dll ที่นำไปใช้ใน project อื่นๆ ได้ ผู้ที่นำไปใช้เพียงแค่ add reference ถึงไฟล์นี้ก็จะสามารถเรียกใช้ type Foo ได้โดยระบุ FQCN เป็น CsharpBook.Chapter04.Foo ดังตัวอย่างต่อไปนี้

class Bar

{

    CsharpBook.Chapter04.Foo myFoo = new CsharpBook.Chapter04.Foo();

}

หากผู้นำไลบราลีไปใช้ไม่ต้องการระบุ FQCN เพราะยืดยาวเกินไป ก็สามารถนำ namespace CsharpBook.Chapter04 ผนวกเข้ากับ namespace ของตนได้ จะทำให้สามารถอ้างถึง type Foo ได้เหมือนกับเป็น type ที่อยู่ภายใน namespace ของตน ดังตัวอย่างต่อไปนี้

 

using CsharpBook.Chapter04;
namespace mySpace
{
     class Bar
     {
          Foo myFoo = new Foo();
     }
}

 

ท่านอาจจะคิดเสียว่า namespace คือครอบครัวหนึ่ง ทุกคนในครอบครัวมีนามสกุลเดียวกัน มี 195 ครอบครัวที่สืบเชื่อสายมาจากตระกูลเดียวกันคือ System.Object

เหตุผลที่ผู้สร้าง .NET Framework ตัดสินใจแยกหมวดหมู่คลาสในไลบรารีออกเป็น namespace นอกจากจะเพื่อความสะดวกในการเรียกใช้แล้ว ยังเพื่อป้องกันปัญหาเรื่องการตั้งชื่อคลาสซ้ำกันด้วย ยกตัวอย่างเช่นหากใน namespace aa มีคลาสชื่อ a ใน namespace bb ก็สามารถมีคลาสชื่อ a ได้ด้วย

ผู้สร้าง .NET Framework สนับสนุนให้ผู้เขียนโปรแกรมบน .NET Framework สร้าง namespace ของตนเองขึ้น หาก namespace ครอบคลุม source code ไฟล์หลายไฟล์ จะเรียกกลุ่มไฟล์ที่ประกอบเป็น name space เดียวกันว่า แอสเซมบลี (Assembly อย่าสับสนกับภาษาแอสเซมบลี กรุณาอ่านรายละเอียดเรื่องแอสเซมบลีในหัวข้อถัดไป) ในหนึ่งแอสเซมบลีอาจประกอบด้วยหลาย namespace ก็ได้

สรุปว่า namespace คือวิธีจัดหมวดหมู่ของคลาส โดยใช้ keyword namespace ตามด้วยชื่อของ namespace หากมี namespace ซ้อนกันหลายชั้นให้ใช้เครื่องหมาย จุด ขั้นระหว่าง namespace คลาสใดๆ ที่อยู่ภายในวงเล็บปีกกาของ namespace จะถือว่าเป็นคลาสที่อยู่ใน namespace เดียวกัน

นอกจากคลาสภายใน namespace อาจประกอบด้วยสิ่งอื่น เช่น struc, Interface, Delegate และ enum เป็นต้น

มิใช้เฉพาะไลบรารีที่เราสร้างขึ้นเองที่ใช้หลัก namespace เช่นนี้ แต่ Microsoft .NET Framework Library ก็ใช้หลักการนี้เช่นกัน (ดูรายละเอียดในบทที่ 2 หัวข้อ วิธีเขียนโค้ดเรียกใช้งาน FCL)

แนวคิดเรื่อง namespace ก็เหมือนกับเรื่อง type ที่ไม่ใช่เรื่องของเฉพาะภาษา C# เท่านั้น ภาษาอื่นๆ ใน .NET ล้วนเป็นไปตามแนวคิดนี้ทั้งสิ้น (Java ก็ใช้แนวคิดเดียวกันนี้ด้วย) แต่เนื่องจากภาษา C# เป็นภาษาหลักของ .NET Framework แนวคิดเรื่อง namespace และ type จึงไม่สามารถแยกออกจากภาษา C# ได้

 

Type ในภาษา C#

เมื่อท่านสร้างซอฟท์แวร์ด้วยภาษา C# ท่านจะพบว่าท่านใช้เวลาส่วนใหญ่ไปกับการตรวจหา type ที่ต้องการจาก .NET Framework class library ส่วนเวลาที่เหลือจะหมดไปกับการออกแบบและสร้าง type ของท่านเอง

ในหนังสือเล่มนี้ท่านจะพบคำว่า type บ่อยที่สุด และคำว่า “คลาส” รองลงมา บางครั้งผู้เขียนก็ใช้สองคำนี้สลับกันไปมา สาเหตุที่เป็นเช่นนั้นเพราะหัวใจของ .NET Framework (และ Java platform ด้วย) คือ Type เมื่อท่านเขียนโค้ดในสภาพแวดล้อม .NET ท่านจะหนีเรื่อง Type ไปไม่พ้น เพราะทุกสิ่งทุกอย่างใน .NET Framework คือ type ทั้งนั้น

ผู้สร้าง .NET Framework ต้องการให้ทุกภาษาปราศจาก pointer และทำทุกอย่างได้ด้วย type ทุกภาษาใน .NET จึงมีคุณสมบัติ Type-safe ซึ่งช่วยป้องกันมิให้โปรแกรมเข้าถึงตำแหน่งในหน่วยความจำที่ไม่ได้รับอนุญาต โปรแกรมที่ทำงานใน .NET Framework จึงไม่กวนระบบ นี่เป็นจุดแข็งข้อหนึ่งของ .NET

ในเมื่อเราสามารถใช้ type สร้าง object ได้ คำพูดว่าทุกสิ่งทุกอย่างใน .NET มาจาก type ก็เท่ากับพูดว่าทุกสิ่งทุกอย่างใน .NET มีสภาพเป็น object ไปหมด และเมื่อตรวจสอบการสืบสันดานย้อนขึ้นไปแล้วท่านจะพบว่า object ทั้งหมดล้วนสืบทอดมาจากบรรพบุรุษเดียวกัน ต้นตระกูลที่ว่านี้คือ type ที่มีชื่อว่า System.Object

นอกจาก System.Object แล้ว ใน .NET Framework ยังมี type จำนวนมากเตรียมไว้ให้ท่านเลือกใช้ คือมีอยู่ประมาณ 7,500 คลาส แม้จะมีจำนวนมาก การเลือกใช้คลาสเหล่านี้กลับไม่ยาก เพราะมันถูกจัดหมวดหมู่ไว้เป็นอย่างดี หมวดหมู่เหล่านี้เรียกว่าnamespace ซึ่งคลาสไลบรารีจะถูกแบ่งออกเป็น namespace ทั้งหมดจำนวน 195 namespace ตามประเภทการใช้งาน

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

int foo;

เป็นการสร้างตัวแปรที่มี data type เป็นแบบจำนวนเต็ม (integer) คำว่า type ในบริบทนี้มีมานานแล้วตั้งแต่สมัยภาษาซีใน Unix ภาษา C# ก็มี data type ในลักษณะนี้ (บางทีเรียก build-in data type) แต่คำว่า type ใน .NET Framework กินความกว้างกว่านั้นเพราะมี type ที่เกิดจากคลาสด้วย

หมายเหตุ: data type กับ abstract data มีความคล้ายคลึงกัน ยกเว้นว่าหากพูดถึง abstract data มักหมายถึงการนิยามทั้งชนิดของข้อมูล และวิธีที่ operator กระทำกับ type ใดๆ

ต้นตอของ type (ที่มาจากคลาส) เริ่มในช่วงทศวรรษ 1960 เมื่อนักคอมพิวเตอร์ชาว นอร์เวย์ กลุ่มหนึ่งได้คิดประดิษฐ์ภาษา Simula (อ่านว่าซิมูลา) ขึ้นมา หลักการคิดของภาษานี้ให้ความหมายใหม่ให้แก่คำว่า type ซึ่งเป็นนิยามที่ตรงกับคำว่า type ที่เรากำลังพูดถึงกันอยู่ขณะนี้ เพราะคณะบุคคลที่ออกแบบ .NET Framework ได้ยึดถือหลักการบางอย่างที่มีในภาษา Simula ด้วย และเป็นการยึดถือแบบสุดขั้ว เพราะผู้ออกแบบ .NET Framework ได้เปลี่ยนทุกสิ่งทุกอย่างให้กลายเป็น type ไปทั้งหมดแม้แต่ primitive type (อย่าง integer) บัดนี้ได้กลายเป็น type ในนิยามแบบนี้ไปแล้วเช่นกัน

สาเหตุที่ผู้สร้าง .NET Framework ทำเช่นนี้ก็เพราะต้องการลดความซับซ้อนในการเขียนโปรแกรมสำหรับระบบปฏิบัติการ Windows การเขียนโปรแกรมแบบ Win32 ท่านต้องเรียนรู้วิธีเรียกใช้ฟังก์ชัน API ต่างๆ ที่มีเพิ่มขึ้นเรื่อยๆ ฟังก์ชันจำนวนมากที่มีลักษณะซ้ำซ้อน ทำให้นักเขียนโปรแกรมเริ่มมองว่าการเขียนโปรแกรมสำหรับทำงานในระบบปฏิบัติการ Windows ยุ่งยากมาก

ทีมผู้สร้าง .NET Framework แก้ปัญหานี้โดยนักเขียนโค้ดยุติการเขียนโปรแกรมแบบเรียกใช้ฟังก์ชัน API (รวมทั้ง Microsoft foundation class ด้วย) แล้วสร้าง Framework class library ขึ้นมาแทน โดยไลบรารีนี้มีคลาสต่างๆ ประมาณ 7,500 คลาสๆ เหล่านี้มีจุดเด่นที่สามารถสืบทอดคุณสมบัติตามลำดับได้ ทำให้การเพิ่มเติมคุณสมบัติใหม่ๆ เข้าไปใน Framework สามารถทำได้โดยไม่เกิดการซ้ำซ้อน ยกตัวอย่างเช่น เมื่อทีมงานต้องการเพิ่ม method ให้คลาสใด ก็สามารถใช้ชื่อซ้ำกับ method ที่มีอยู่แล้วได้ เพียงแค่กำหนด signature ของ method ใหม่ให้แตกต่างจากเดิมก็ใช้ได้แล้ว (คือการทำ method overloading โปรดอ่านรายละเอียดเรื่อง method overloading ในบทที่ 4)

 

Value type

ความเข้าใจว่า type คืออะไร ตัวแปรคืออะไร value type กับ reference type เหมือนหรือแตกต่างกันอย่างไร เป็นสิ่งสำคัญอย่างที่สุดในการเขียนโปรแกรมทุกภาษา โดยเฉพาะอย่างยิ่งภาษา C# ดังนั้นขอให้ท่านอ่านสองหัวข้อต่อไปนี้ให้เข้าใจ ลองดูตัวอย่างโปรแกรมต่อไปนี้

int foo = 4;

int bar = 12;

foo = foo + bar;

บรรทัดแรกคำสั่ง int เป็น keyword ในภาษา C# ทำหน้าที่กำหนด type (primitive type) ของตัวแปร คำว่า int ย่อมาจากคำว่า integer (อ่านว่าอินทีเจอร์ แปลว่าเลขจำนวนเต็ม) การเก็บเลขจำนวนเต็มแบบ int ของ .NET จะใช้เนื้อที่ในหน่วยความจำขนาด 32 บิต หากใช้เพื่อเก็บจำนวนเต็มลบและจำนวนเต็มบวกจะเก็บค่าได้สูงสุดภายในย่าน -2,147,483,648 ถึง 2,147,483,647

สมมุติว่าผู้เขียนคอมไพล์โปรแกรมนี้ และสั่งให้ทำงาน CLR (Common Language Runtime เป็นส่วนหนึ่งของ .NET) จะทำหน้าที่จัดสรรหน่วยความจำ (คือ RAM ที่อยู่บนเมนบอร์ด) เพื่อใช้เก็บข้อมูลต่างๆ ในโปรแกรม เมื่อ CLR เห็นคำสั่ง int foo = 4; (ซึ่งอยู่ในสภาพโค้ดภาษาเครื่อง) มันจะสร้างกล่องใบหนึ่ง เป็นกล่องที่มีความโตขนาด 32 บิต และติดป้ายชื่อไว้ว่า foo (คำว่า foo ไม่มีความหมายอะไรพิเศษ จะใช้ชื่ออะไรก็ได้) จากนั้น CLR จะนำเลข 4 ไปใส่ในกล่องนี้ (ดูภาพ 303)

 

ภาพ 303: CLR จองหน่วยความจำขนาด 32 บิตเพื่อเก็บค่า int

 

ในภาพ 303 ท่านจะเห็นหน่วยความจำ RAM มีสภาพเป็นกล่องสิบสองใบ (ในการใช้งานจริงอาจมีหลายล้าน ใบ) หนึ่งใบเท่ากับ 8 บิต หรือหนึ่งไบต์ เมื่อเราใช้คำสั่ง int CLR จะรู้ทันทีว่าต้องจองพื้นที่ในหน่วยความจำสี่ไบต์ (เพราะสี่ไบต์เท่ากับ 32 บิต) มันจึงจองไบต์ที่ 1 ถึงไบต์ที่ 4 ไว้และติดป้ายชื่อไว้ว่า foo ซึ่งเป็นชื่อของตัวแปรที่เรากำหนด จากนั้น CLR จะนำเลข 4 ไปใส่ไว้ในหน่วยเก็บข้อมูลนี้

int bar = 12;

คำสั่งบรรทัดต่อมาผู้เขียนสร้างตัวแปรชื่อ bar และนำเลข 12 ไปเก็บไว้ เมื่อโปรแกรมทำงานบรรทัดนี้เสร็จ สภาพในหน่วยความจำจะเป็นดังที่เห็นในภาพ 304

 

ภาพ 304: สภาพของหน่วยความจำเมื่อสร้างตัวแปร bar เสร็จแล้ว

 

foo = foo + bar;

คำสั่งบรรทัดนี้สั่งให้นำค่าของตัวแปร foo มาบวกกับค่าของตัวแปร bar ได้ผลลัพธ์เท่าใดให้นำไปเก็บไว้ในตัวแปร foo (ดูภาพ 305)

 

ภาพ 305 การนำค่าจากตัวแปรสองตัวมาบวกกัน

 

ค่าของตัวแปร foo คือ 4 นำมาบวกกับค่าของตัวแปร bar ซึ่งเป็น 12 ผลลัพธ์ที่ได้คือ 16 CLR จะนำค่านี้ไปเก็บไว้ในตัวแปร foo ดังนั้นเมื่อโปรแกรมนี้จบการทำงาน ค่าของตัวแปร foo จะเท่ากับ 16 (ดูภาพ 306)

 

ภาพ 306: สภาพของหน่วยความจำหลังจากทำคำสั่งสุดท้ายเสร็จแล้ว

 

จากตัวอย่างโปรแกรมที่อธิบายมานี้ท่านจะเห็นว่าตัวแปรเก็บค่าโดยตรง เมื่อมีการเปลี่ยนแปลงค่า (ในตัวอย่างคือผลลัพธ์จากการบวก) สิ่งที่เก็บอยู่ในตัวแปรก็จะเปลี่ยนไปโดยตรง การเก็บข้อมูลลักษณะนี้เรียกว่า value type

ในภาษา C# สิ่งที่เป็น value type คือบรรดาตัวแปรชนิดจำนวนเต็มต่างๆ (integral type) จำนวนมีทศนิยม (floating-point และ decimal type) ตัวแปรแบบ บูลลีน และโครงสร้างข้อมูลที่ผู้ใช้กำหนดเอง (user defined type หรือ struct)

ต่อไปลองดูโปรแกรมตัวอย่างที่เป็น struct บ้าง

 

public struct Sample

{

     public int foo;

}

 

นี่คือโค้ดที่จะสร้างโครงสร้างข้อมูลแบบผู้ใช้กำหนดเองหรือ struct ผู้เขียนตั้งชื่อมันว่า Sample และผู้เขียนกำหนดให้ struct ตัวนี้มีสมาชิกเพียงตัวเดียวชื่อ foo ซึ่งเป็นตัวแปรแบบเลขจำนวนเต็ม

 

Sample first = new Sample

first.foo = 5;

Sample second = first;

first.foo = 6;

Console.writeLine(second.foo);

 

คำสั่งบรรทัดแรกสร้าง object ชื่อ first จาก struct บรรทัดที่สองนำ 5 ไปเก็บในตัวแปร foo ซึ่งเป็นสมาชิกของ object ชื่อ first บรรทัดที่สามสร้าง object อีกตัวชื่อ second บรรทัดที่สี่นำ 6 ไปเก็บในตัวแปร foo ของ object second บรรทัดสุดท้ายสั่งให้แสดงค่าในตัวแปร foo ของ object second บนจอภาพ ท่านคิดว่าผลลัพธ์ที่ได้คืออะไร

 

คำตอบคือ 5

 

ทำไมจึงเป็นเช่นนั้น? สาเหตุที่เป็นเช่นนั้นเพราะทั้ง first และ second เป็น object ที่ถูกสร้างจาก struc มันจึงเป็น object แบบ value type และเนื่องจาก object ที่เป็น value type มีที่เก็บข้อมูลเป็นของตัวเองในหน่วยความจำ เมื่อเราเปลี่ยนแปลงค่าของ first ค่าของ second จะไม่เปลี่ยนตามไปด้วย

เรื่อง value type เป็นเรื่องปรกติธรรมดา ที่พบได้ทั่วไปในภาษาคอมพิวเตอร์ต่างๆ ยกตัวอย่างเช่น ในภาษาแอสเซมบลี value type เทียบได้กับการอ้างถึงหน่วยความจำแบบ direct addressing

เวลาสร้างตัวแปรแบบ value type ท่านต้องกำหนดค่าให้มันด้วย (initial หรือ assign) มิฉะนั้นเมื่อนำไปใช้จะเกิด compile-time error ยกตัวอย่างเช่น

 

int foo;

int bar = 12;

int foo = foo + bar;

 

หากท่านคอมไพล์โปรแกรมนี้ ตัวแปลภาษาจะแจ้งว่าบรรทัดที่สามมีความผิดพลาด เพราะเรานำตัวแปร foo ที่ถูกสร้างแล้วจากบรรทัดที่หนึ่ง แต่ยังไม่ได้ถูกกำหนดค่า (unassigned) ไปใช้งาน ข้อความแจ้งความผิด (error message) ที่ตัวแปลภาษาแสดงคือ Use of unassigned local variable ‘foo’

ตอนต่อไป : Reference type

ตอน 12 : เปรียบเทียบภาษา C# กับภาษาอื่นๆ

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

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

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

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

 

 

เปรียบเทียบภาษา C# กับภาษาอื่นๆ

ถ้าพูดถึงความใกล้เคียงกับภาษาอื่นๆ ภาษา C# ใกล้เคียงกับภาษา Java มากที่สุด โดยมีความเหมือนกันถึง 70% ดั้งนั้นนักเขียนโปรแกรมภาษา Java จึงอาจย้ายมาเขียนภาษา C# ได้โดยศึกษาว่ามีสิ่งใดที่แตกต่างกันบ้าง ภาษา C# ยังมีความคล้ายคลึงกับภาษ C++.NET และภาษา VB.NET เป็นอย่างมาก ทำให้นักเขียนโปรแกรมภาษา C# สามารถอ่าน-เขียนโค้ดในภาษากลุ่มนี้ได้เมื่อฝึกฝนเพียงเล็กน้อย

ยกตัวอย่างความเหมือนกันระหว่างภาษา C# และภาษา Java คือเรื่องการสืบสันดาน (Inheritance) ทั้งคู่เป็นแบบสืบจากคลาสหลักได้คลาสเดียว ขณะที่ภาษา C++ สามารถสืบจากคลาสหลักได้มากกว่าหนึ่ง (Multiple inheritance) โดยภาษา C# และภาษา Java ใช้ Interface มาทดแทน Multiple inheritance เหมือนกันทั้งคู่ อีกตัวอย่างหนึ่งที่ภาษา C# และ Java มีร่วมกันคือเรื่อง Garbage Collection ซึ่งมีทั้งใน C# และ Java แต่ไม่มีใน C++ จึงทำให้ดูเหมือนว่าภาษา Java ต่อยอดมาจากภาษา C++ และ C# ต่อยอดมาจาก Java อีกที แต่ถูกดัดแปลงให้แตกต่างออกไปมากพอที่บริษัท ซัน จะไม่อาจฟ้องร้องว่าไมโครซอฟท์ลอกเลียนภาษา Java

 

ภาพ 303: เครื่องแม่ข่าย Sun Fire V40z ของบริษัท Sun Microsystems เจ้าของภาษา Java

 

ที่เป็นเช่นนั้นเพราะทั้ง Java และ C# มีต้นสายมาจาก C++ ทำให้สองภาษานี้ดูคล้ายกัน แต่ภาษา C# ไม่ใช่ภาษา Java มันมีกลไกที่เป็นเอกลักษณ์หลายอย่าง เช่น พารามิเตอร์แบบ reference และ output การจัดเก็บ object ไว้ใน stack (struct) การทำ Versioning และยังมีสิ่งใหม่ๆ ที่เป็น “ของดี” มอบให้นักเขียนโปรแกรมหลายอย่าง เช่น delegate, properties และ operator overloading ซึ่งท่านจะไม่พบในภาษา Java

ภาษา C# มีอะไรดี

ผู้เขียนขอแนะนำว่าถ้าท่านคิดจะเขียนโปรแกรมใน .NET เป็นโปรแกรมง่ายๆ เล็กๆ น้อยๆ ท่านควรใช้ภาษา VB.NET แต่ถ้าท่านต้องการเขียนโปรแกรมที่ซับซ้อนขึ้น เช่น โปรแกรมควบคุมฮาร์ดแวร์ และโปรแกรมเกมสามมิติ ท่านควรเรียนรู้ภาษา C# ไว้ด้วย เพราะแม้ .NET จะมีภาษาให้เลือกใช้หลายสิบภาษา แต่ภาษา C# เป็นพื้นเมืองของ .NET เมื่อค้นใน web จะพบข้อมูลและตัวอย่างโค้ดเป็นภาษา C# มากกว่าภาษาอื่น

บิดาของภาษา C# คือ Hejlsberg กล่าวว่า “จุดขาย” ของภาษา C# มีสี่ประการดังนี้

เป็นภาษาที่เน้นชิ้นส่วน (Component oriented)

แนวคิดเรื่องซอฟท์แวร์ชิ้นส่วนมีมานานแล้ว เหมือนเลโก้ (ของเด็กเล่น) ที่เป็นบล็อกพลาสติกเล็กๆ สีสดใด ถูกออกแบบไว้อย่างดี ทำให้สามารถนำมาใช้ต่อกันเป็นอะไรได้สารพัด ภาษา C# เอื้ออำนวยการใช้งานลักษณะนี้ โดยให้ท่านสร้าง properties method และ event เองได้ง่ายๆ เป็นเอกสารอธิบายการทำงานไปในตัว (คือผลิตเอกสาร XML จาก source code ได้เลย) การดึงโค้ดที่ท่านเคยเขียนไว้มาใช้ก็ทำได้ง่าย ไม่ต้องทำเป็นไฟล์ header ที่ใช้งานไม่ค่อยสะดวก

 

ภาพ 304: ปัจจุบันมีตำราสอนการประยุกต์ใช้ XML อยู่มาก

 

สิ่งต่างๆ เป็น object ทั้งหมด

ในภาษา C++ พวก type พื้นฐานต่างๆ (เช่น int, double) ถือเป็น primitive type คือเป็น type ที่ฝังอยู่ในภาษา จึงดูเหมือนไม่มีที่มาที่ไป เพราะสามารถเรียกใช้ได้อย่างลอยๆ ส่วนภาษา Smalltalk และภาษา Lips พวก type พื้นฐานล้วนเป็น object ซึ่งเป็น reference type ทั้งหมด ทำให้การทำงานมีประสิทธิภาพลดลง ส่วนในภาษา C# แม้ทุกอย่างเป็น object หมด แต่ type พื้นฐานจะมีภาวะเป็น value type จึงไม่ลดทอนประสิทธิภาพ ยกตัวอย่างเช่น

int foo;

นี่คือการนิยามตัวแปรชื่อ foo มี type เป็น int หรือจำนวนเต็ม เนื่องจาก type int แม้จะดูเหมือน type พื้นฐานแต่อันที่จริงมันคือคลาส System.int32 ดังนี้ foo จึงมีภาวะเป็น object แต่จะพิเศษกว่า object ธรรมดาตรงที่มันเป็น value type

foo + 1;

ในตัวอย่างโค้ดข้างบน แม้เลข 1 จะเป็นตัวเลขที่เราพิมพ์เข้าไป (literal) แต่มันก็ยังกลายเป็น object ที่มี type เป็น System.int32 ไปด้วย เนื่องจากทุก type ล้วนสืบสันดานจาก System.Object เลข 1 จึงสามารถเรียกใช้ method ต่างๆ ที่นิยามไว้ใน System.Object ได้ ยกตัวอย่างเช่น

string Bar = 1.ToString();

เป็นภาษาที่ทนทาน

คำว่าทนทาน (robust) ในที่นี้หมายถึงทนต่อความผิดพลาด ไม่ทำให้ระบบแฮงค์หรือระบบอืด ทั้งนี้เพราะภาษา C# มีของดีสี่อย่างคือ (1) Garbage collection เป็นกลไกบริหารหน่วยความจำเพื่อทำลาย object ที่หมดเงื่อนไขในการดำรงอยู่ ป้องกันความเผอเรอของนักเขียนโปรแกรมที่ทำให้เกิดอาการ “หน่วยความจำรั่ว” (memory leaks) (2) Exceptions เป็นตัวดักจับและรายความความผิดพลาดแบบ run-time error (3) Type-safety ป้องกันการเรียกใช้ตัวแปรที่ยังไม่ได้ถูกกำหนดค่าเริ่มต้น ป้องกันการ casts ที่ไม่ปลอดภัย (4) Versioning เพื่อรักษาความปลอดภัยในการใช้คลาสและการสืบทอด

เขียนโค้ดแล้วไม่เหนื่อยฟรี

ไม่ได้หมายความว่าภาษา C# สามารถช่วยป้องกันไม่ให้ลูกค้าบิดพลิ้วเงินค่าจ้างได้ (หาทำได้คงจะดีเหมือนกัน) แต่หมายถึงภาษา C# จัดเตรียมกลไกไว้หลายอย่างที่ช่วยให้เรานำโค้ดที่เขียนไว้ใน “โปรเจค” หนึ่งไปใช้กับอีกโปรเจคหนึ่งได้ง่าย นอกจากนั้นภาษา C# ยังสามารถเรียกใช้คลาสหลายพันคลาสใน .NET Framework ได้โดยตรง ทำให้ลดเวลาการพัฒนาซอฟท์แวร์ได้มาก

ปรัชญาในการออกแบบภาษา C#

มาตรฐาน ECMA ระบุว่าภาษา C# มีปรัชญาการออกแบบดังนี้

  • เป็นภาษา OOP ยุคใหม่ที่เน้นความเรียบง่าย อเนกประสงค์
  • สนับสนุนหลักวิศวกรรมซอฟท์แวร์ เช่น มีการตรวจสอบ type ตรวจสอบขอบเขตของอาร์เรย์
  • ใช้เขียนงานประมวลผลแบบกระจายได้
  • การนำ source code ไปใช้กับระบบ (platform) ต่างๆ กันถือว่ามีความสำคัญ
  • การใช้ได้กับทุกประเทศถือว่าสำคัญ
  • สามารถสร้างซอฟท์แวร์ได้ทั้งขนาดใหญ่ และในระบบปฏิบัติการของอุปกรณ์พกพา
  • เน้นประหยัดหน่วยความจำและกำลังของหน่วยประมวลผล แต่ไม่ถึงขนาดภาษา C หรือแอสเซมบลี

คุณสมบัติอื่นๆ

ต่อไปนี้เป็นคุณสมบัติที่ท่านจะพบในภาษา C# แต่ไม่มีในภาษา C++

  • ไม่มีตัวแปรหรือ method โดดๆ ตัวแปรและ method ทุกตัวต้องเป็นสมาชิกของคลาส
  • ในบล็อกเดียวกันใช้ตัวแปรชื่อเดียวกันไม่ได้
  • ไม่มีฟังก์ชันที่อยู่ลอยๆ เรียกใช้ได้จากทุกแห่ง (อย่าง printf() ใน C)
  • มี name space สืบทอดกันเป็นลำดับชั้น
  • type ทั้งหมดแม้กระทั่ง primitive (เช่น int หรือ double) ล้วนมีที่มาจากคลาส
  • ค่าบูลลีนเมื่อใช้เป็นนิพจน์ตรวจสอบ (เช่นใน if) จะใช้สลับกับค่า int อย่างใน C++ ไม่ได้
  • ภาษา C# สนับสนุนตัวแปรแบบพอยน์เตอร์ (pointer) แต่ต้องใช้ในส่วน unsafe
  • Garbage collection ทำหน้าที่ตัดสินใจว่าจะทำลาย object ตัวใดเมื่อใด
  • Hejlsberg ตัดสินใจว่าไม่ต้องการใช้ภาษา C# มี multiple inheritance
  • เป็นภาษาที่เข้มงวดเรื่อง type

คุณสมบัติที่เพิ่มขึ้นในเวอร์ชัน 2.0

  • Partial class ช่วยให้เขียนคลาสเดียวแยกเป็นหลายไฟล์ได้
  • Generics คล้ายๆ template ในภาษา C++
  • คลาสแบบ static เป็นคลาสที่นำไปใช้สร้าง object ไม่ได้ แต่ช่วยให้ทำตัวแปรและ method แบบ global ได้
  • เพิ่ม Iterator และ yield คล้ายคลึง yield ในภาษา Python
  • Anonymous delegate ช่วยให้เขียนการทำงานแบบ Call back ได้ง่ายขึ้น
  • signature แบบ Covariance และ contravariance สำหรับ delegate
  • ค่าแบบ Nullable เพื่อความสะดวกในการเขียนโค้ดติดต่อกับฐานข้อมูลแบบ SQL

คุณสมบัติที่เพิ่มขึ้นในเวอร์ชัน 3.0

  • เพิ่มคำสั่ง from, where, select เพื่อทำงานกับ SQL
  • เพิ่มวิธีสร้าง object และการกำหนดค่าเริ่มต้นแบบใหม่ที่ช่วยให้เขียนโค้ดได้กระชับขึ้น
  • นิพจน์แลมดา (Lambda expression) ช่วยให้เขียนโค้ดได้กระชับขึ้น
  • type แบบ anonymous ช่วยให้การกำหนด type ทำได้คล่องตัวขึ้น
  • ตัวแปรท้องถิ่นที่มี type เป็น implicit
  • อาร์เรย์ที่มี type เป็น implicit
  • method แบบ extension ช่วยให้สามารถต่อเติม method ใหม่ให้ type ได้
  • Expression trees ทำให้มองนิพจน์แลมดาเป็นข้อมูล (แทนที่จะเป็นโค้ด) ได้

ตอนต่อไป: โปรแกรม Hello World

ตอน 11 : ภาษา C# ระดับพื้นฐาน

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

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

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

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

 

 

นักเขียนโค้ดภาษา C# ไม่มีวันตาย พวกเขาเพียงแค่ cast ไปเป็น void

นักเขียนโค้ดนิรนาม

 

บทที่ 3: ภาษา C# ระดับพื้นฐาน

 

ในบทนี้และอีกสองบทถัดไปท่านจะได้เรียนเรื่องพื้นฐานที่จำเป็นต้องรู้เกี่ยวกับภาษา C# สิ่งที่ผู้เขียนจะสอนไม่ใช่คำสั่งต่างๆ ในภาษา C# อย่างคำสั่ง if หรือคำสั่งวนรอบ เช่น คำสั่ง for คืออะไร เขียนอย่างไร มีไวยากรณ์อย่างไร เพราะนี่ไม่ใช่หนังสือรวบรวมคำสั่งภาษา C# คำสั่งเหล่านี้ท่านสามารถดูได้จากเอกสาร MSDN ในเว็บไซต์ หรือจะ download มาติดตั้งไว้ในเครื่องของท่านก็ได้

สิ่งที่ผู้เขียนกำลังจะสอนท่านในหนังสือเล่มนี้คือแนวความคิด ซึ่งเป็นวิธีคิดที่ท่านจำเป็นต้องมีเพื่อจะเขียนภาษา C# ได้อย่างมีประสิทธิภาพ อาทิ เรื่อง namespace และเรื่อง type เป็นต้น หัวข้อสำคัญต่างๆ ที่ท่านจะได้เรียนในบทนี้คือ

 

  • โครงสร้างของโปรแกรมในภาษา C#
  • namespace
  • Type ในภาษา C#
  • Value type
  • Reference type
  • การทำ Boxing และ Unboxing
  • การสร้างคลาส
  • stuct
  • หลักการตั้งชื่อในภาษา C#
  • นิพจน์ในภาษา C# (Expression)
  • การประกาศ (Declaration)

ภาพ 301: Microsoft Visual C# .net

ชื่อภาษา C#

ภาษา C# จะเขียนว่า C Sharp ก็ได้ (อ่านว่าซีชาร์พ) เครื่องหมาย # ในทางดนตรีหมายถึงครึ่งเสียง ส่วนคำว่า Sharp หมายถึงเฉียบคม มีไหวพริบ บริษัทไมโครซอฟท์ตั้งชื่อภาษานี้ว่า C# เพื่อจะสื่อให้เห็นว่านี่คือภาษาในตระกูลภาษา C เช่นเดียวกับภาษา C++ คือเป็นภาษาที่มีต้นกำเนิดจากภาษา C หากท่านสังเกตให้ดีจะเห็นว่าสัญลักษณ์ # จะมองให้เป็นเครื่องหมาย + สี่อันนำมาซ้อนกันก็ได้ แสดงเป็นนัยว่าภาษานี้ก้าวหน้ากว่าภาษา C++ ไปอีกระดับหนึ่ง (คือเป็นภาษา C++++) สัญลักษณ์ # นี้มีปรากฏในภาษาอื่นๆ ของ .NET ด้วย เช่นภาษา J#(เดิมคือภาษา J++) และภาษา A# (เหมือนภาษา Ada) อาจเป็นเพื่อเหตุผลการการค้า

ภาษา C# คืออะไร

ภาษา C# เป็นภาษาที่ใหม่มากๆ ปรากฏตัวเป็นครั้งแรกในปี 2000 และถูกอัพเดตเวอร์ชันอยู่เสมอ มันเป็นภาษาที่ได้รับอธิพลจากภาษาก่อนหน้าเช่นภาษา Delphi ภาษา C++ ภาษา Java และภาษา Eiffel ในตอนต้นภาษานี้ถูกออกแบบ และกำหนดลักษณะโดยบริษัทไมโครซอฟท์ ต่อมาได้ถูกรับรองจากหน่วยงาน ECMA (หน่วยงานกำหนดมาตรฐานสากลด้านสารสนเทศ) และ ISO แต่ปัจจุบันไมโครซอฟท์ยังพัฒนาภาษานี้อย่างต่อเนื่อง (ปัจจุบันเป็นเวอร์ชัน 3.0)

ภาษา C# ถูกพัฒนาขึ้นโดยเป็นส่วนหนึ่งในการพัฒนาโครงสร้างพื้นฐานของ .NET Framework เป็นการการนำข้อดีของภาษาต่างๆ (เช่นภาษา Delphi ภาษา C++) มาปรับปรุงเพื่อให้มีความเป็น OOP อย่างถึงที่สุด ขณะเดียวกันก็ลดความซับซ้อนในโครงสร้างของภาษาลง (เรียบง่ายกว่าภาษา C++) และมีเครื่องแต่งตัวน้อยลง (เมื่อเทียบกับ Java)

ภาพ 302: Delphi คือภาษา Pascal แบบ OOP ของบริษัท Borland

ผู้สร้างภาษา C#

ผู้สร้างภาษา C# คือบริษัทไมโครซอฟท์ แต่บิดาของภาษา C# คือ Anders Hejlsberg (แอนเดรส ฮาเยสเบิร์ก) ไมโครซอฟท์ต้องการให้ภาษา C# เป็น “อะไรที่จะอยู่ไปอีกนาน” เหมือนบริษัทรถยนต์โฟลค์ที่จ้าง Ferdinand Porsche (เฟอร์ดินันด์ พอร์ช) นักออกแบบรถยนต์มือดีมาออกแบบรถโฟลคเต่า (เป็นเหตุการณ์ที่เกิดขึ้นก่อนสงครามโลกครั้งที่สอง) ทำให้มันกลายเป็นรถยนต์คลาสสิกมาจนถึงปัจจุบัน ในทำนองเดียวกันเมื่อต้องการภาษาที่ต้องการให้กลายเป็นภาษา “คลาสสิก” บริษัทไมโครซอฟท์ตัดสินใจมอบหมายให้ Hejlsberg บรมครูนักออกแบบภาษา ผู้เคยสร้างภาษาที่กลายเป็นตำนานมาแล้วเช่น Turbo Pascal และผู้นำในทีมสร้างภาษา Delphi

ใครๆ ก็สร้างภาษาใหม่ได้ไม่ยาก แต่ภาษาที่ดีจริงๆ นั้นเป็นอีกเรื่องหนึ่ง สำหรับภาษา C# Hejlsberg ไม่เพียงสร้างภาษาที่ใช้งานได้ดีเท่านั้น เขายังเน้น “ความมีรสนิยม” และ “ความสง่างาม” เพราะต้องการให้โปรแกรมเมอร์เขียนโปรแกรมภาษา C# ได้อย่างมีความสุข

ภาพ 301 Anders Hejlsberg บิดาของภาษา C#

 

ตอนต่อไป: เปรียบเทียบภาษา C# กับภาษาอื่นๆ

ตอน 10: วิธีเขียนโค้ดเรียกใช้งาน FCL


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


 

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

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

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

 

ตอน 10: วิธีเขียนโค้ดเรียกใช้งาน FCL

 

การเรียกใช้ type ที่อยู่ภายใน FCL ทำได้สองแบบ แบบแรกเรียกว่า fully-qualified class name (ต่อไปจะเรียกย่อว่า FQCN) และ non-qualified class name (ต่อไปจะเรียกย่อว่า NQCN) การเรียกใช้สองแบบแตกต่างกันดังนี้

FQCN เป็นการเรียกใช้คลาสโดยระบุ namespace อย่างเต็มยศ โปรดพิจารณาตัวอย่างโค้ดดังต่อไปนี้

 

using System;
using System.Collections.Generic;
using System.Text;

namespace test
{
     class Program
     {
          static void Main(string[] args)
               {
                   System.IO.Ports.SerialPort myPort = new System.IO.Ports.SerialPort();
               }
     }
}

 

โปรแกรมนี้เรียกใช้คลาส SerailPort ซึ่งเป็นคลาสหนึ่งใน namespace Ports ซึ่งเป็น namespace ที่มี base namespace เป็น IO และ System ตามลำดับ

โปรดสังเกตว่าโปรแกรมนี้ก็มี namespace ของมันเองด้วย (ชื่อ test) เราสามารถนำ namespace หลายๆ namespace มาผนวกเข้าด้วยกันได้โดยใช้คำสั่ง using (เหมือนคำสั่ง import ในภาษา Java) เมื่อผนวกแล้วจะสามารถอ้างถึงคลาสใน namespace นั้นได้โดยตรงแบบ NQCN โปรดพิจารณาตัวอย่างโค้ดดังต่อไปนี้

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;

namespace ConsoleApplication3
{
     class Program
     {
          static void Main(string[] args)
          {
               SerialPort myPort = new SerialPort();
          }
     }
}

 

ท่านคงจะเห็นด้วยกับผู้เขียนว่าการอ้างชื่อคลาสแบบ NQCN ดีกว่า FQCN เพราะอ่านโปรแกรมเข้าใจได้ง่ายกว่าเนื่องจากโค้ดไม่รกไปด้วย namespace ยาวๆ

 

ภาพ 204: เอกสารใน MSDN เป็นข้อมูลจากผู้ผลิต FCL โดยตรงจึงมีความเชื่อถือได้และได้รับการปรับปรุงให้ทันสมัยอยู่เสมอ

 

เอกสารอ้างอิงที่ให้ข้อมูลเกี่ยวกับ FCL คือ MSDN หรือ Microsoft Development Network ซึ่งมีทั้งแบบ off-line (ในซีดีรอม) และแบบ on-line (ในอินเตอร์เน็ต msdn2.microsoft.com) เอกสารใน MSDN เป็นข้อมูลจากผู้ผลิต FCL โดยตรงจึงมีความเชื่อถือได้ และได้รับการปรับปรุงให้ทันสมัยอยู่เสมอ

 

สรุปท้ายบท

เทคโนโลยี Microsoft .NET Framework ทำให้การสร้างโปรแกรมประยุกต์ทำได้ง่ายและรวดเร็วขึ้น เราสามารถใช้เครื่องมือ .NET สร้างโปรแกรมประยุกต์ได้หลายรูปแบบ เช่นโปรแกรมประยุกต์สำหรับเครื่องคอมพิวเตอร์แบบตั้งโต๊ะ เครื่องคอมพิวเตอร์แบบพกพา เครื่องเล่นเกม (X-Box) โทรศัพท์มือถือ และโปรแกรมประยุกต์ที่ทำงานในอินเตอร์เน็ต

ในบทนี้ผู้เขียนได้ให้ข้อมูลโดยสังเขป เพียงเท่าที่จำเป็นต้องรู้เกี่ยวกับ Microsoft .NET Framework เพื่อให้ท่านสามารถศึกษาเนื้อหาในบทต่อๆ ไปได้ ในบทต่อไปท่านจะได้เรียนเรื่องพื้นฐานของภาษา C# ซึ่งเป็นภาษาที่เราจะใช้เป็นเครื่องมือเพื่อศึกษาหลักการ OOP และวิธีสร้างเว็บไซต์

 

คำถามท้ายบท

  1. CLR ย่อมาจากอะไร มีหน้าที่อะไร
  2. compiler ของภาษา C# ทำหน้าที่แปล source code ให้เป็นภาษาอะไร
  3. รูปแบบโปรแกรมประยุกต์ที่  .NET Framework สนับสนุนมีอะไรบ้าง
  4. การประมวลผลแบบกระจายคืออะไร
  5. โค้ดภาษาเครื่อง ภาษาเครื่อง (native machine code) คืออะไร
  6. managed code คืออะไร
  7. PE คืออะไร
  8. MSIL คืออะไร
  9. CLR จะแบ่งหน่วยความจำ (RAM) ในเครื่องคอมพิวเตอร์ออกเป็นกี่แบบ
  10. โครงสร้างข้อมูลแบบ stack เป็นอย่างไร
  11. Heap คืออะไร
  12. Finalize ทำหน้าที่อะไร
  13. namespace คืออะไร

เฉลยคำถาม

ตอนต่อไป: บทที่ 3 ภาษา C# ระดับพื้นฐาน

ตอน 9 : เรื่องของ managed code


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

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

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

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

 

 

เรื่องของ managed code

 

หากท่านสร้างโปรแกรมด้วยเครื่องมือที่ไม่ใช่ .NET ผลลัพธ์ที่ได้จะเป็นโค้ดภาษาเครื่อง (native machine code) อยู่ในรูปของไฟล์ .exe หรือ .dll ที่เก็บข้อมูลเป็น binary (อ่านว่าไบนารี แปลว่าเลขฐานสอง) ซึ่งวินโดวส์สามารถนำไปดำเนินการได้โดยตรง วินโดวส์ (ระบบปฏิบัติการ) จะทำหน้าที่เรียกให้โปรแกรมทำงาน จัดสรรหน่วยความจำ แต่จะไม่รับรู้การทำงานของโปรแกรม และไม่รับประกันสิ่งผิดพลาดที่อาจเกิดขึ้น (เช่นโปรแกรมอ้างถึง array element ที่เกินขอบเขต) โปรแกรมลักษณะนี้ไม่ใช่ managed code (เรียก unmanaged code)

เมื่อท่านสร้างโปรแกรมด้วยเครื่องมือที่เป็น MNF ผลลัพธ์ที่ได้จะเป็นโค้ดภาษากลาง (Microsoft Immediate language หรือ MSIL) อยู่ในรูปของไฟล์ .exe หรือ .dll ที่เก็บข้อมูลเป็น binary เช่นเดียวกัน แต่วินโดวส์ไม่สามารถนำไปดำเนินการได้ MNF จะทำหน้าที่เรียกให้โปรแกรมทำงาน จัดสรรหน่วยความจำ สร้างและทำลาย object ในโปรแกรม MNF จะรับรู้การทำงานของโปรแกรมตลอดเวลา และจะแจ้งเตือนเมื่อมีสิ่งผิดพลาดเกิดขึ้น (เช่นโปรแกรมอ้างถึง array element ที่เกินขอบเขต) โปรแกรมลักษณะนี้คือ managed code

 

ภาพ 204: Java Runtime Environment

 

หลักการเช่นนี้คล้ายภาษา Java โดยตัวแปลภาษา Java จะผลิตผลลัพธ์เป็น ไบต์โค้ด (byte code) ซึ่งทำงานได้กับคอมพิวเตอร์ทุกชนิด (platform) ที่ติดตั้งโปรแกรม J2SE Runtime Environment ไว้

managed code แปลว่าโค้ดที่ถูกจัดการ หมายถึงโปรแกรมที่เราเขียนได้รับการดูแลจัดการ ไม่ได้ถูกปล่อยให้ทำงานไปโดยขาดการควบคุมอย่าง unmanaged code ผู้ทำหน้าที่ดูแลจัดการดังกล่าวนี้คือส่วน CLR ของ MNF นั่นเอง

 

เรื่องของ CLR

CLR หรือ Common Language Runtime คือส่วนประกอบสำคัญอย่างหนึ่งของ MNF หน้าที่ของ CLR มีดังต่อไปนี้

  • แปลโปรแกรมประยุกต์จากภาษา MSIL ให้เป็นรหัสภาษาเครื่อง
  • เรียกให้รหัสภาษาเครื่องที่แปลแล้วทำงาน
  • จัดสรรหน่วยความจำ
  • รับประกันความถูกต้องของ type (type safety)
  • ดูแลด้านความปลอดภัยของโค้ดที่ทำงาน
  • จัดให้มีการแจ้งเตือนความผิดพลาดแบบ runtime error
  • สนับสนุนการทำงานหลายกระบวนการ (multi-thread)
  • สนับสนุนการแก้ไขโปรแกรม (debug)

 

ภาพ 205: CLR มีองค์ประกอบทั้งหมด 11 ส่วน

 

  1. CLR มีองค์ประกอบทั้งหมด 11 ส่วนดังต่อไปนี้
  2. ทำหน้าที่โหลดคลาสเข้าสู่ CLR
  3. ทำหน้าที่แปลภาษา MSIL เป็นภาษาเครื่อง
  4. ทำหน้าที่บริหารโค้ดระหว่างการทำงาน
  5. ทำหน้าที่จัดสรรหน่วยความจำและ Garbage collection
  6. ตัวจัดการด้านการแก้ไขโปรแกรม
  7. ตัวตรวจสอบความเข้ากันของ type
  8. ตัวตรวจสอบความปลอดภัย
  9. ตัวแจ้งเตือนเมื่อเกิดความผิดพลาด
  10. ตัวทำให้โปรแกรมประยุกต์แลกเปลี่ยนข้อมูลกับโปรแกรมแบบ COM ได้
  11. ตัวสนับสนุนการทำงานหลายกระบวนการ
  12. ตัวทำให้โปรแกรมประยุกต์สามารถเรียกใช้ type ต่างๆ ของ MNF ได้

 

ในเรื่อง CLR มีคำจาร์กอนหลายคำที่ท่านควรรู้ความหมาย คือ PE, assembly, JIT, Garbage collector, metadata, native code และ MSIL ผู้เขียนจะอธิบายความหมายโดยย่อของแต่ละคำดังต่อไปนี้

  • PE ย่อจาก Portable Executable หมายถึงไฟล์ที่ได้จากการคอมไพล์ภาษา MNF เช่นภาษา C# ให้เป็นภาษา MSIL แล้ว
  • assembly ในหนึ่งงานอาจได้ผลลัพธ์เป็น PE หลายๆ ไฟล์ ทั้งหมดเรียกรวมกันว่า assembly
  • JIT ย่อจาก Just In Time คือการแปลภาษา MSIL ให้เป็นภาษาเครื่องขณะ runtime โดยโปรแกรมจะถูกแปลเฉพาะส่วนที่กำลังทำงานเป็นส่วนๆ ไป
  • Garbage collector การรวบรวม object ในหน่วยความจำที่ไม่ใช้แล้วมาทำลายเพื่อพื้นฟูพื้นที่ว่างในหน่วยความจำ
  • metadata เกิดจากสองคำคือคำว่า meta หมายถึง “เหนือ” และ data คือข้อมูล ในที่นี้หมายถึง “ข้อมูลที่ใช้พรรณนาข้อมูลอื่น” CLR ใช้ metadata เพื่อรับรู้ลักษณะของ type หนึ่งๆ และลักษณะที่ type นั้นอ้างอิงถึง type อื่นๆ
  • native code หมายถึงโค้ดที่ถูกแปลเป็นภาษาเครื่องแล้ว (คือภาษาที่จำเพาะเจาะจงให้ทำงานกับ CPU ตระกูลใดตระกูลหนึ่ง)
  • MSIL ย่อจาก MicroSoft Immediate Language คือภาษาใหม่ที่บริษัท Microsoft ประดิษฐ์ขึ้นเพื่อเป็นภาษาระดับกลางใน MNF ตัวแปลภาษาระดับสูง (VB.NET, C#, J#) ทุกภาษาจะแปลโค้ดโปรแกรมประยุกต์ที่เขียนด้วยภาษาระดับสูงให้เป็นภาษา MSIL จากนั้น CLR จะแปลเป็น native code ขณะโปรแกรมประยุกต์ทำงานอีกครั้งหนึ่ง

 

ภาพ 206: โดยใช้ JIT ทำให้ CLR สามารถตรวจพบความผิดพลาดที่เกิดขึ้นขณะโปรแกรมทำงานได้ (runtime error) เช่นการเรียกใช้พอร์ทสื่อสารที่ไม่มีหรือไม่ว่าง

 

การจัดสรรหน่วยความจำ

สถาปัตยกรรม .NET Framework นอกจากจะมีส่วนที่เป็นคลาสไลบรารีแล้ว ยังมีส่วนสำคัญมากอีกส่วนหนึ่งชื่อ Common language runtime หรือเรียกย่อๆ ว่า CLR ทำหน้าที่โหลด (load) โค้ดโปรแกรมที่คอมไพล์แล้วของเรา (อยู่ในสภาพของภาษา intermediate language หรือ MSIL คือภาษาระดับกลาง) มาคอมไพล์ซ้ำอีกครั้งให้กลายเป็น native code หรือ machine code ที่ซีพียูสามารถนำไปปฏิบัติได้

นอกจากมีหน้าที่คอมไพล์แบบ runtime แล้ว CLR ยังมีหน้าที่จัดสรรหน่วยความจำด้วย เมื่อ object ถูกสร้างขึ้นจากคลาส CLR จะทำหน้าที่จัดสรรหน่วยความจำให้โดยอัตโนมัติ นั่นหมายความว่าโปรแกรมเมอร์ไม่ต้องทำหน้าที่จองและปลดปล่อยหน่วยความจำหน่วยความจำด้วยตนเอง

เมื่อเราสร้าง object CLR จะจองหน่วยความจำให้เรา และเมื่อ object จบบทบาทลงกลไกของ .NET Framework อีกตัวหนึ่งมีชื่อว่า garbage collector (คนเก็บขยะ) จะทำหน้าที่ “เวนคืน” พื้นของหน่วยความจำบริเวณนั้น ทำให้หน่วยความจำเป็นอิสระเพื่อให้ CLR จะนำไปใช้จัดสรรให้ object อื่นๆ ที่ถูกสร้างขึ้นใหม่ต่อไป

CLR จะแบ่งหน่วยความจำ (RAM) ในเครื่องคอมพิวเตอร์ออกเป็นสองส่วนคือ stack (อ่านว่า สแตก) และ heap (อ่านว่า ฮีพ) โดยจะใช้ stack เพื่อเก็บสิ่งที่มีพลวัตสูง เช่น ลำดับของกระบวนการในคำสั่ง (อย่างการ call ไปยังเมธอด) และข้อมูลที่ต้องการเข้าถึงตามลำดับก่อนหลัง ส่วน heap จะถูกใช้เพื่อเก็บส่วนข้อมูลสมาชิกของ object ทั้ง stack และ heap เป็นโครงสร้างข้อมูล (data structure) ปรกติธรรมดาที่ท่านคงเคยเรียนมาแล้วในวิชาเขียนโปรแกรมขั้นพื้นฐาน หากท่านลืมหมดแล้วก็ไม่เป็นไร เพราะผู้เขียนจะทบทวนความจำให้

 

เรื่องของ stack

โปรแกรมเมอร์บางคนได้ยินคำว่า stack แล้วรู้สึกวิงเวียนคล้ายจะเป็นลม เพราะคิดว่าเป็นเรื่องสูงส่งที่มีแต่โปรแกรมเมอร์ที่องค์การนาสาเท่านั้นที่บังอาจเข้าใจได้ ไม่จริงเลย อันที่จริง stack มีหลักการง่ายๆ ที่แม้แต่พนักงานล้างจานก็เข้าใจได้ดี

โครงสร้างข้อมูลแบบ stack เป็นการเก็บข้อมูลแบบซ้อนทับกัน เหมือนเวลาเราล้างจาน เราจะนำจานที่ล้างแล้วมาเรียงกันเป็นตั้ง ใบที่ล้างเสร็จใบแรกจะอยู่ล่างสุดของตั้ง ใบที่ล้างเสร็จใบถัดไปก็จะนำมาวางซ้อนไว้เหนือใบแรก ซ้ำอย่างนี้ไปเรื่อย เราจะไม่พยายามแทรกใบที่ล้างเสร็จใหม่เข้าไปตรงกลาง เมื่อต้องการหยิบใช้ เราจะหยิบใบที่อยู่บนสุดของตั้งมาใช้ก่อน เราจะไม่พยายามดึงจานใบที่อยู่ตรงกลางหรือล่างออกมาก่อน

การเก็บข้อมูลใน stack ก็เช่นเดียวกัน ข้อมูลที่ถูกนำมาไว้ใน stack ก่อน จะลงไปอยู่ล่างสุดของ stack ข้อมูลใหม่จะถูกนำไปซ้อนไว้เหนืออันแรก และซ้อนกันไปเรื่อยเช่นนี้ ดังนั้นข้อมูลที่เข้าไปใน stack ก่อนจะออกไม่ได้ จนกว่าข้อมูลที่อยู่เหนือมันถูกนำออกไปหมดแล้ว เราจึงต้องนำข้อมูลที่ใส่เข้าไปภายหลังออกมาให้หมดเสียก่อน หลักการเช่นนี้เรียกว่า “เข้าก่อนออกที่หลัง” (first in, last out หรือเรียกย่อว่า LIFO ไลโฟ)

 

ภาพ 207 โครงสร้างข้อมูลแบบ stack ใน .NET Framework มีลักษณะเหมือน stack ธรรมดา โดยด้านล่างของ stack คือตำแหน่ง 0 (Loc 0) ตำแหน่งบนสุด (stack top) คือตำแหน่งที่ถัดจากข้อมูลใน stack เมื่อข้อมูลถูกนำมาเก็บใน stack ข้อมูลที่มาอันแรกจะถูกเก็บที่ตำแหน่ง 0 ข้อมูลต่อไปจะถูกเก็บที่ตำแหน่ง 1 ไล่เรียงไปเช่นนี้ และค่าของ stack pointer (ตัวชี้ตำแหน่งยอดของ stack) ก็จะถูกเพิ่มค่าขึ้นทุกครั้ง

 

เมื่อโปรแกรมเรียกเมธอด โค้ดในเมธอดจะถูก CLR นำมาใส่ไว้ใน stack (push) ที่ตำแหน่งบนสุดจากนั้นพารามิเตอร์ของเมธอดจะถูกมาซ้อนไว้ข้างบน และแปรท้องถิ่นภายในเมธอดจะถูกนำไปซ้อนไว้ในตำแหน่งที่สูงขึ้นไปอีก

เมื่อข้อมูลถูกเรียกออกจาก stack ข้อมูลบนสุดของ stack จะถูกดึงออกไป (pop) ก่อนและ stack pointer จะถูกลดค่าลงเพื่อชี้ไปยังข้อมูลตัวถัดไปใน stack

เมื่อโปรแกรมของเราเรียกการทำงานไปยังเมธอด โค้ดในเมธอดจะถูก CLR นำมาซ้อนไว้บน stack ตามด้วยพารามิเตอร์ของเมธอด ขณะที่โปรแกรมทำงานตามคำสั่งต่างๆ ในเมธอด และพบกับตัวแปรท้องถิ่นภายในเมธอด CLR จะนำค่าของตัวแปรขึ้นไปซ้อนไว้บนยอดของ stack อีกชั้นหนึ่ง

 

เรื่องของ heap

เมื่อโปรแกรมของเราเริ่มทำงาน CLR จะจองเนื้อที่ในหน่วยความจำ (RAM บนเมนบอร์ด) เป็นพื้นที่ต่อเนื่องไว้ส่วนหนึ่ง โดยยังไม่ตกลงใจว่าจะใช้เก็บอะไร พื้นที่ดังกล่าวนี้เรียกว่า managed heap หรือ heap เมื่อมีการ “นิว” (การใช้ operator new เพื่อสร้างอินสแตนซ์ของคลาส) CLR จึงจะจัดสรรพื้นที่ใน heap เพื่อเก็บสมาชิกทั้งหลายของ object และกำหนด pointer เพื่อชี้ไปยังพื้นที่ว่างถัดไป หากมีการสร้าง object อีกก็จะมีการจัดสรรพื้นที่ใน heap อีก (และเลื่อน pointer ด้วย) ดังนั้น object ที่ถูกสร้างจากคลาสทุกตัวจะมีที่เก็บข้อมูลสมาชิกเป็นของตัวเอง

 

ภาพ 208: Heap ใน unmanaged code จะถูกสร้างจากโครงสร้างข้อมูลแบบ binary tree ที่แต่ละ node จะอยู่กระจายกันในหน่วยความจำ แต่ heap ของ managed code จะเป็นพื้นที่ติดกันทั้งหมดจึงทำงานได้เร็วกว่า

 

การทำงานที่พูดถึงในย่อหน้าบนเป็นวิธีบริหารหน่วยความจำ (manage memory) ของ MNF แต่ถ้าท่านต้องการเขียนโปรแกรมแบบไม่ให้ MNF บริหารหน่วยความจำ (unmanaged memory) ก็สามารถทำได้ ในกรณีนี้ heap จะไม่ใช่พื้นที่ต่อเนื่องกัน แต่จะเป็นพื้นที่ในหน่วยความจำตรงโน้นบ้างตรงนี้บ้าง ที่ถูกเชื่อมโยงด้วยลิงค์ลิสต์ ดังนั้นการทำงานแบบ managed จะเร็วกว่าเพราะ heap จะมีสภาพเป็นพื้นที่ต่อเนื่องกัน ส่วน unmanaged จะทำงานช้ากว่า เพราะเมื่อโปรแกรมต้องการเข้าถึงส่วนเก็บข้อมูลใดๆ มันจะต้องท่องไปในลิงค์ลิสต์จนกว่าจะพบส่วนของ heap ที่ต้องการ

 

เรื่องของ garbage collector

ในการทำงานแบบ manage memory ส่วน garbage collector (ต่อไปจะเรียกย่อๆ ว่า GC) ซึ่งเป็นกลไกอย่างหนึ่งของ MNF ที่คอยตรวจสอบรายการ object ภายใน heap อยู่เสมอ หากพบว่า object ใดไม่อยู่ในขอบเขตการใช้งานแล้ว มันจะพิจารณาว่า object นั้นเป็นขยะ (garbage)

GC จะแบ่ง object ที่ถือกำเนิดและอาศัยอยู่ใน heap ออกเป็นสามชั่วรุ่น คือ 0, 1 และ 2 โดยชั่วรุ่น 0 เป็นชั่วรุ่นที่เพิ่งเกิดใหม่ GC จะรวบรวม object ชั่วรุ่นที่ 0 ที่ไม่อยู่ในขอบเขตการใช้งานแล้วเอาไว้ และจะปรับระดับ object ที่ยังถูกใช้งานอยู่ให้เป็นชั่วรุ่นที่ 1 และ 2 ตามลำดับ เมื่อถึงเวลาที่เหมาะสม GC จะทำลาย object ที่ไม่อยู่ในขอบเขตการใช้งานแล้วในชั่วรุ่นที่ 0 เมื่อ heap ชั่วรุ่นที่ 0 เริ่มมีพื้นที่ไม่เพียงพอสำหรับการสร้าง object ใหม่ GC จะเริ่มตรวจดูชั่วรุ่นที่ 1 และ 2 ตามลำดับ เพื่อทำลาย object ที่พ้นสมัยแล้ว

 

ภาพ 209: ภาพโครงสร้างของ heap และและการทำงานของ GC

 

เรื่องของ Dispose และ Finalize

ผู้เขียนอธิบายเรื่องการบริหารหน่วยความจำของ MNF เพื่อให้ท่านเข้าใจว่า GC ทำลายเฉพาะสิ่งที่อยู่ใน heap เท่านั้น หาก object ของเราเรียกใช้ทรัพยากรอื่นๆ ที่เป็น unmanaged resort เช่น เปิดไฟล์ข้อมูล เชื่อมต่อกับฐานข้อมูล เชื่อมต่อกับเครือข่าย จองใช้พื้นที่ขนาดใหญ่ในหน่วยความจำ ฯลฯ คงจะดีหากเราปลดปล่อยทรัพยากรเหล่านี้ก่อนที่ object จะถูกทำลายโดย GC

ในกรณีที่ object ของเราสืบสันดานมาจาก object อื่น ย่อมเป็นความคิดที่ดีเช่นกัน หากเราจะปลดปล่อยทรัพยากรที่ base class เรียกใช้แต่ยังไม่ได้ปลดปล่อยด้วย

คลาสที่ใช้ทรัพยากรแบบ unmanaged resort มักมีเมธอดแบบ pubic ชื่อ Dispose อยู่ด้วย คำสั่งในเมธอดนี้เป็นคำสั่งใช้ทำหน้าที่ปลดปล่อย unmanaged resort ต่างๆ เมธอด Dispose มีไว้เพื่อให้โค้ดที่สร้าง object จากคลาสนี้สามารถปลดปล่อยทรัพยากรที่ object นั้นจองไว้ได้

ปัญหาอย่างหนึ่งของเมธอด Dispose คือผู้ใช้มักลืมเรียกเมธอดนี้ทำให้ทรัพยากรต้องค้างเติ่งอยู่หลังจาก GC ทำลาย object ไปแล้ว .NET Framework จึงจัดเตรียมกลไกอย่างหนึ่งไว้เป็นเมธอดชื่อ Finalize ทำหน้าที่เป็นเหมือนยามคอยเฝ้าระวัง หากโค้ดที่สร้าง object ลืมเรียก Dispose เพื่อปลดปล่อย unmanaged resort เมธอด Finalize จะทำหน้าที่เรียก Dispose ให้โดยอัตโนมัติ

ตั้งแต่ต้นของบทนี้จนถึงหัวข้อนี้ ท่านได้รับรู้ข้อมูลเบื้องต้นทั้งหมดเกี่ยวกับ CRL ไปแล้ว แต่ MNF ยังมีส่วนสำคัญอีกส่วนหนึ่งคือ class library ดังจะอธิบายในหัวข้อต่อไป

 

แนะนำ .NET Framework class library

ภาษา C# ไม่มี runtime library ของมันเองโดยเฉพาะต่างหาก runtime library ของภาษา C# คือ .NET Framework class library ซึ่งมันใช้ร่วมกับภาษา .NET อื่นๆ ทุกภาษา

.NET Framework class library (ต่อไปจะเรียกย่อว่า FCL) เป็นแหล่งรวม คลาส interface และ value type ต่างๆ ประมาณ 2,500 ตัว สามารถเรียกใช้ได้จากทุกภาษาที่เป็นภาษาสำหรับ .NET (คือภาษาที่สร้างตาม common language specification หรือ CLS)

 

ภาพ 210: หนังสืออ้างอิง .NET Framework class library ของสำนักพิมพ์ Microsoft Press

 

FCL จัดให้มีคลาสต่างๆ ที่จำเป็นต้องใช้ในการเขียนโปรแกรมทั่วๆ ไป อาทิ

  • คลาสที่ทำหน้าที่เป็น data type พื้นฐาน (อย่าง int)
  • คลาสที่ encapsulate โครงสร้างข้อมูล
  • คลาสที่ใช้เพื่อติดต่อกับโลกภายนอก
  • คลาสเรียกการตรวจสอบความปลอดภัย
  • คลาสเพื่อเข้าถึงข้อมูล
  • คลาสเพื่อจัดให้มีส่วนติดต่อกับผู้ใช้เป็นกราฟิกอย่างเพียบพร้อม (rich client-side GUI)

คลาสใน FCL มีทั้งคลาสที่นำไปใช้โดยตรงก็ได้ หรือจะนำไปใช้เป็น base class เพื่อสืบสันดานเป็นคลาสใหม่ก็ได้ (เรียกว่า concrete class) และมีคลาสที่นำไปใช้โดยตรงไม่ได้ ต้องนำไปใช้เป็น base class ได้เท่านั้น (เรียกว่า abstract class)

เช่นเดียวกับที่ปรากฏในภาษา Java (ที่เรียก package) เพื่อให้ใช้งานได้ง่าย FCL แบ่งคลาสต่างๆ ออกเป็นหมวดหมู่เรียกว่า namespace โดยมี namespace ทั้งหมดดังนี้

Accessibility
IEHost.Execute
Microsoft.Aspnet.Snapin
Microsoft.Build.BuildEngine
Microsoft.Build.Framework
Microsoft.Build.Tasks
Microsoft.Build.Tasks.Deployment.Bootstrapper
Microsoft.Build.Tasks.Deployment.ManifestUtilities
Microsoft.Build.Tasks.Hosting
Microsoft.Build.Utilities
Microsoft.CLRAdmin
Microsoft.CSharp
Microsoft.IE
Microsoft.JScript
Microsoft.JScript.Vsa
Microsoft.SqlServer.Server
Microsoft.VisualBasic
Microsoft.VisualBasic.ApplicationServices
Microsoft.VisualBasic.CompilerServices
Microsoft.VisualBasic.Devices
Microsoft.VisualBasic.FileIO
Microsoft.VisualBasic.Logging
Microsoft.VisualBasic.MyServices
Microsoft.VisualBasic.MyServices.Internal
Microsoft.VisualBasic.Vsa
Microsoft.VisualC
Microsoft.Vsa
Microsoft.Vsa.Vb.CodeDOM
Microsoft.Win32
Microsoft.Win32.SafeHandles
Microsoft.WindowsCE.Forms
Microsoft.WindowsMobile.DirectX
Microsoft.WindowsMobile.DirectX.Direct3D
Microsoft_VsaVb
RegCode
System
System.CodeDom
System.CodeDom.Compiler
System.Collections
System.Collections.Generic
System.Collections.ObjectModel
System.Collections.Specialized
System.ComponentModel
System.ComponentModel.Design
System.ComponentModel.Design.Data
System.ComponentModel.Design.Serialization
System.Configuration
System.Configuration.Assemblies
System.Configuration.Install
System.Configuration.Internal
System.Configuration.Provider
System.Data
System.Data.Common
System.Data.Design
System.Data.Odbc
System.Data.OleDb
System.Data.OracleClient
System.Data.Sql
System.Data.SqlClient
System.Data.SqlServerCe
System.Data.SqlTypes
System.Deployment.Application
System.Deployment.Internal
System.Diagnostics
System.Diagnostics.CodeAnalysis
System.Diagnostics.Design
System.Diagnostics.SymbolStore
System.DirectoryServices
System.DirectoryServices.ActiveDirectory
System.DirectoryServices.Protocols
System.Drawing
System.Drawing.Design
System.Drawing.Drawing2D
System.Drawing.Imaging
System.Drawing.Printing
System.Drawing.Text
System.EnterpriseServices
System.EnterpriseServices.CompensatingResourceManager
System.EnterpriseServices.Internal
System.Globalization
System.IO
System.IO.Compression
System.IO.IsolatedStorage
System.IO.Ports
System.Management
System.Management.Instrumentation
System.Media
System.Messaging
System.Messaging.Design
System.Net
System.Net.Cache
System.Net.Configuration
System.Net.Mail
System.Net.Mime
System.Net.NetworkInformation
System.Net.Security
System.Net.Sockets
System.Reflection
System.Reflection.Emit
System.Resources
System.Resources.Tools
System.Runtime
System.Runtime.CompilerServices
System.Runtime.ConstrainedExecution
System.Runtime.Hosting
System.Runtime.InteropServices
System.Runtime.InteropServices.ComTypes
System.Runtime.InteropServices.CustomMarshalers
System.Runtime.InteropServices.Expando
System.Runtime.Remoting
System.Runtime.Remoting.Activation
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Http
System.Runtime.Remoting.Channels.Ipc
System.Runtime.Remoting.Channels.Tcp
System.Runtime.Remoting.Contexts
System.Runtime.Remoting.Lifetime
System.Runtime.Remoting.Messaging
System.Runtime.Remoting.Metadata
System.Runtime.Remoting.Metadata.W3cXsd2001
System.Runtime.Remoting.MetadataServices
System.Runtime.Remoting.Proxies
System.Runtime.Remoting.Services
System.Runtime.Serialization
System.Runtime.Serialization.Formatters
System.Runtime.Serialization.Formatters.Binary
System.Runtime.Serialization.Formatters.Soap
System.Runtime.Versioning
System.Security
System.Security.AccessControl
System.Security.Authentication
System.Security.Cryptography
System.Security.Cryptography.Pkcs
System.Security.Cryptography.X509Certificates
System.Security.Cryptography.Xml
System.Security.Permissions
System.Security.Policy
System.Security.Principal
System.ServiceProcess
System.ServiceProcess.Design
System.Text
System.Text.RegularExpressions
System.Threading
System.Timers
System.Transactions
System.Transactions.Configuration
System.Web
System.Web.Caching
System.Web.Compilation
System.Web.Configuration
System.Web.Configuration.Internal
System.Web.Handlers
System.Web.Hosting
System.Web.Mail
System.Web.Management
System.Web.Mobile
System.Web.Profile
System.Web.RegularExpressions
System.Web.Security
System.Web.Services
System.Web.Services.Configuration
System.Web.Services.Description
System.Web.Services.Discovery
System.Web.Services.Protocols
System.Web.SessionState
System.Web.UI
System.Web.UI.Adapters
System.Web.UI.Design
System.Web.UI.Design.MobileControls
System.Web.UI.Design.MobileControls.Converters
System.Web.UI.Design.WebControls
System.Web.UI.Design.WebControls.WebParts
System.Web.UI.HtmlControls
System.Web.UI.MobileControls
System.Web.UI.MobileControls.Adapters
System.Web.UI.MobileControls.Adapters.XhtmlAdapters
System.Web.UI.WebControls
System.Web.UI.WebControls.Adapters
System.Web.UI.WebControls.WebParts
System.Web.Util
System.Windows.Forms
System.Windows.Forms.ComponentModel.Com2Interop
System.Windows.Forms.Design
System.Windows.Forms.Design.Behavior
System.Windows.Forms.Layout
System.Windows.Forms.PropertyGridInternal
System.Windows.Forms.VisualStyles
System.Xml
System.Xml.Schema
System.Xml.Serialization
System.Xml.Serialization.Advanced
System.Xml.Serialization.Configuration
System.Xml.XPath
System.Xml.Xsl
System.Xml.Xsl.Runtime

 

แต่ละ namespace อาจประกอบด้วย คลาส interface และ value type จำนวนหนึ่ง ยกตัวอย่างเช่น namespace ชื่อ System.IO.Ports ทำหน้าที่อำนวยความสะดวกในการเขียนโปรแกรมเพื่อติดต่อกับ port สื่อสารอนุกรม namespace นี้มีคลาสอยู่ภายในสี่คลาส delegate สามตัว และ enumeration หกตัว

ในแต่ละ namespace จะมีการแบ่งกลุ่มย่อยออกมาอีก โดยทุก namespace มี base namespace ชื่อ System และ namespace นั้นอาจมี namespace ย่อยอีกหลายตัว ยกตัวอย่างเช่น namespace ชื่อ System.Xml มี base ชื่อ System ตัวมันเองชื่อ Xml และ namespace System.Xml มี namespace ย่อยอีก 7 กลุ่มคือ

  • System.Xml.Schema
  • System.Xml.Serialization
  • System.Xml.Serialization.Advanced
  • System.Xml.Serialization.Configuration
  • System.Xml.XPath
  • System.Xml.Xsl
  • System.Xml.Xsl.Runtime

โปรดสังเกตว่าชื่อของ namespace แต่ละกลุ่มจะมีเครื่องหมายจุดคั่น namespace ทางซ้ายจะเป็น base namespace ของ namespace ทางขวา ยกตัวอย่างเช่น namespace System.Xml.Schema จะมี namespace System เป็น base namespace ของ namespace Xml และ namespace Xml จะเป็น base namespace ของ namespace Schema

ใน MNF คำว่า namespace มีสองความหมาย ที่กล่าวถึงในย่อหน้าบนคือ class library namespace ยังมี namespace อีกชนิดหนึ่งคือ namespace ของผู้เขียนโปรแกรมประยุกต์

 

ตอนต่อไป: วิธีเขียนโค้ดเรียกใช้งาน FCL

ตอน 8 : .NET Framework และคลาสไลบรารี

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


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

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

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

 

 

บทที่ 2 .NET Framework และคลาสไลบรารี

เมื่อท่านต้องการนำโปรแกรมที่ท่านเขียนด้วยภาษา C# ไปใช้ในคอมพิวเตอร์เครื่องใด คอมพิวเตอร์นั้นจะต้องติดตั้งโปรแกรม Microsoft .NET Framework ไว้ก่อน หากท่านสร้าง Web application ด้วยภาษา C# ท่านต้องติดตั้ง Web application นั้นไว้ใน web server ที่เป็น ASP.NET server ซึ่งมี .NET Framework ติดตั้งอยู่เช่นกัน ส่วนผู้ใช้งาน Web application ของท่านไม่จำเป็นต้องมี .NET Framework ก็ได้

Microsoft .NET Framework (อ่านว่าไมโครซอฟท์ ดอตเนต เฟรมเวิร์ค ต่อไปจะเรียกโดยย่อว่า MNF) คือชิ้นส่วนซอฟท์แวร์ (software component) ที่เพิ่มเข้าไปในระบบปฏิบัติการวินโดวส์ ของบริษัทไมโครซอฟท์ ประกอบด้วยโปรแกรมต่างๆ ที่จัดเตรียมไว้ให้นักเขียนโค้ด ซึ่งเป็นโปรแกรมย่อยต่างๆ ที่ใช้เพื่อต่อยอด สร้างโปรแกรมประยุกต์ใช้งานทั่วๆ ไป และยังมีส่วนจัดการโปรแกรมที่เขียนขึ้นเพื่อทำงานใน MNF โดยเฉพาะ MNF เป็นหัวใจหลักที่บริษัทไมโครซอฟท์เจตนาให้นักเขียนโค้ดทั่วไปใช้เพื่อสร้างซอฟท์แวร์ประยุกต์ใหม่ๆ ในระบบปฏิบัติการวินโดวส์

 

ภาพ 201: หน้าเว็บเกี่ยวกับ .NET Framework ในเว็บไซต์ MSDN

 

โปรแกรมต่างๆ ที่จัดเตรียมไว้ให้นักเขียนโค้ดคือส่วนที่เรียกว่า คลาสไลบรารี (class library) ครอบคลุมการเขียนโปรแกรมในด้านต่างไว้อย่างกว้างขวาง อาทิ ส่วนติดต่อกับผู้ใช้ ส่วนติดต่อกับฐานข้อมูล ส่วนเข้ารหัสข้อมูล อัลกอริทึมทางคณิตศาสตร์ และส่วนสื่อสารกับระบบเครือข่าย โดยนักเขียนโปรแกรมจะนำคลาสไลบรารีมาผนวกกับโค้ดที่ตนเขียนเพื่อผลิตเป็นโปรแกรมประยุกต์

โปรแกรมที่เขียนขึ้นเพื่อให้ทำงานภายใต้ MNF จะถูกควบคุมการทำงานภายใต้ตัวจัดการสภาพแวดล้อมที่เรียกว่า Common Language Runtime (อ่านว่า คอมมอน แลงเกวจ รันทามน์ ต่อไปจะเรียกย่อว่า CLR) ตัว CLR ทำหน้าที่สร้างเครื่องคอมพิวเตอร์เทียม (virtual machine เป็นซอฟท์แวร์ที่ทำงานอยู่ในคอมพิวเตอร์ที่มี MNF) ทำให้ผู้เขียนโปรแกรมประยุกต์ไม่ต้องกังวลถึงลักษณะของ CPU ในเครื่องที่จะนำโปรแกรมไปใช้งาน นอกจากนั้น CLR ยังจัดให้มีระบบรักษาความปลอดภัย ส่วนบริหารหน่วยความจำ และส่วนจัดการกับความผิดพลาด

คลาสไลบรารีและ CLR คือองค์ประกอบหลักของ MNF (ดังที่เห็นในภาพ 202) เพื่อให้การสร้างโปรแกรมประยุกต์ทำได้ง่ายขึ้น ลดความเสี่ยงต่อการรบกวนกันระหว่างโปรแกรมประยุกต์และระบบปฏิบัติการ MNF เริ่มถูกเผยแพร่เมื่อปี ค.ศ. 2002 มันถูกผนวกไว้กับ Windows Server 2003 และ Windows Vista สามารถทำงานได้ใน Windows 98 และวินโดวส์ที่ใช้ในคอมพิวเตอร์พกพา เวอร์ชันปัจจุบันคือเวอร์ชัน 2.0 ออกเมื่อธันวาคม ค.ศ. 2500 และใช้ง่านร่วมกับ Visual Studio 2005

 

ภาพ 202: องค์ประกอบพื้นฐานในการพัฒนาโปรแกรมสำหรับ .NET กรอบบนสุดคือภาษาสำหรับ .NET ที่บริษัทไมโครซอฟท์จัดไว้ให้สี่ภาษา กรอบกลางคือตัว .NET Framework ที่สนับสนุนทั้งโปรแกรมแบบ desktop application เรียกว่า WinForm และโปรแกรมที่ทำงานในอินเตอร์เน็ตซึ่งใช้เทคโนโลยี ASP.NET โปรแกรมที่ทำงานในอินเตอร์เน็ตมีสองแบบคือ WebForm และ Web Service

ในกรอบกลางจะเห็นว่าองค์ประกอบหลักของ .NET Framework คือ .NET Framework class library และ Common Language Runtime โดย .NET Framework จะทำหน้าที่เป็นตัวกลางระหว่างโปรแกรมประยุกต์และ Microsoft Windows (Win32)

 

การเขียนโปรแกรมภาษา C# เป็นการเขียนโปรแกรมที่ทำงานภายใต้ MNF การทำความเข้าใจกับองค์ประกอบและโครงสร้างของ MNF จึงเป็นสิ่งที่มีประโยชน์ เพราะจะช่วยให้ท่านเข้าใจภาษา C# และการเขียนโปรแกรมใน MNF ได้ดีขึ้น ในบทนี้ผู้เขียนจะแนะนำ บทบาท และหน้าที่ขององค์ประกอบต่างๆ ใน MNF เท่าที่นักเขียนโปรแกรมจำเป็นต้องรู้

เรื่องพื้นฐานที่จำเป็นต้องรู้เกี่ยวกับ .NET Framework

โปรแกรมที่เขียนให้ทำงานใน MNF จะมีความยืดหยุ่นสูง พัฒนาได้รวดเร็ว มีเสถียรภาพดี ปัจจุบันมีตัวแปลภาษาสำหรับ MNF เป็นจำนวนมาก อาทิ Ada, APL, Cobol, Fortran, Java, LISP, RPG, Pascal และอื่นๆ อีกรวมทั้งหมดประมาณ 60 ภาษา (ดูรายการภาษาทั้งหมดได้ที่ http://www.dotnetpowered.com/languages.aspx) ทุกโปรแกรม (ไม่ว่าจะถูกเขียนด้วยภาษาใดก็ตาม) จะถูกแปลเป็นภาษา MSIL (Microsoft Immediate Language ภาษากลางของไมโครซอฟท์) ก่อนจึงจะทำงานภายใต้ MNF ได้ โดย MNF จัดให้มีบริการต่างๆ ดังนี้

บริการของ .NET Framework

  • เครื่องมือสำหรับอำนวยความสะดวกในการพัฒนาโปรแกรมประยุกต์ใช้งาน
  • สภาพแวดล้อมขณะโปรแกรมประยุกต์ทำงาน
  • โครงสร้างพื้นฐานของ server
  • ซอฟท์แวร์อัจฉริยะต่างๆ เพื่อช่วยให้เขียนโค้ดน้อยลงและทำงานได้มีประสิทธิภาพขึ้น

รูปแบบโปรแกรมประยุกต์ที่ .NET Framework สนับสนุน

  • โปรแกรมสำหรับทำงานใน Microsoft Windows
  • โปรแกรมสำหรับทำงานใน Web และ Web service
  • โปรแกรมสำหรับทำงานในอุปกรณ์พกพา เช่นโทรศัพท์มือถือ เครื่อง PDA เครื่องเล่นเกม

เป้าหมายของ .NET Framework

  • เป็นสภาพแวดล้อมเพื่อการพัฒนาโปรแกรมแบบ OOP
  • โปรแกรมประยุกต์สามารถทำงานร่วมกับระบบอินเตอร์เน็ตได้ดี
  • เป็นสภาพแวดล้อมที่ทำให้การติดตั้งโปรแกรมประยุกต์ทำได้ง่าย
  • เป็นสภาพแวดล้อมที่ทำให้การปรับเปลี่ยนเวอร์ชันทำได้ง่าย
  • เป็นสภาพแวดล้อมที่ปลอดภัยจากโปรแกรมที่ทำให้เครื่อง hang
  • การสร้างและการใช้งานโปรแกรมประยุกต์ใน Windows, web และอุปกรณ์พกพาจะมีลักษณะคล้ายคลึงกัน
  • มีมาตรฐานที่ทำให้โปรแกรมใน MNF เข้ากันได้กับโค้ดอื่นๆ

การประมวลผลแบบกระจาย

ความแพร่หลายของระบบเครือข่ายอินเตอร์เน็ต และ intranet (เครือข่ายปิดภายในหน่วยงาน) ทำให้การสร้างซอฟท์แวร์เพื่อให้คอมพิวเตอร์หลายๆ เครื่องทำงานร่วมกันได้เป็นเรื่องจำเป็น ในหนังสือเล่มนี้ผู้เขียนจะสอนวิธีสร้าง Web application ที่เป็น catalog สินค้า การทำงานเช่นนี้เป็นการประมวลผลแบบกระจาย (Distributed computing) ซึ่งมีสถาปัตยกรรมหลายแบบเช่น

  • Peer-to-peer คอมพิวเตอร์ทุกเครื่องในเครื่องข่ายมีความรับผิดชอบเสมอกัน (ไม่มีแม่ข่าย)
  • Client-server มีแม่และลูกข่าย ลูกข่ายมีโค้ดประมวลผลข้อมูลเบื้องต้นจากผู้ใช้ ก่อนส่งข้อมูลให้แม่ข่าย
  • 3-tier architecture มีแม่และลูกข่าย แต่ลูกข่ายไม่ได้ประมวลผล และไม่รับรู้ภาวะของโปรแกรม (stateless)
  • N-Tire architecture เหมือน 3-tire แต่ใช้แม่ข่ายหลายตัวเพื่อประมวลผลงานเดียวกัน

เราสามารถเขียนโปรแกรมใน MNF ได้ทั้งสามสถาปัตยกรรม แต่ Web application ที่ผู้เขียนสอนในหนังสือเล่มนี้จะเป็นแบบสุดท้าย (3-tier ดังที่เห็นในภาพ 203) เพราะการประมวลทั้งหมดเกิดขึ้นที่เครื่องแม่ข่าย

 

ภาพ 203: Distributed computing แบบ 3-Tier

 

ขณะทดสอบเราจะใช้เครื่องคอมพิวเตอร์ของเราทำหน้าที่เป็นแม่ข่าย เมื่อได้ผลลัพธ์ขั้นสุดท้ายแล้วจึงนำโปรแกรมไปติดตั้งไว้ที่เครื่องแม่ข่ายจริงๆ (เรียกว่าการทำ web hosting หรือ web application deployment) เครื่องแม่ข่ายที่ว่านี้คือ ASP.NET web server ที่สนับสนุน .NET 2.0 ในบทสุดท้ายผู้เขียนจะสอนวิธีติดต่อกับ ASP.NET web server ทั้งแบบฟรีเพื่อทดลองใช้ และแบบใช้งานจริงที่ต้องเสียค่าเช่ารายเดือน

 

ตอนต่อไป: เรื่องของ NameSpace

ตอน 7: OOP กับ Microsoft .NET Framework


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


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

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

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

 

 

ตอน 7: OOP กับ Microsoft .NET Framework

 

ในบทต่อไป (บทที่ 2) ทั้งบท ผู้เขียนจะอธิบายรายละเอียดเรื่อง .NET โดยพิสดาร ส่วนในหัวข้อนี้ผู้เขียนจะพูดถึง .NET ในแง่ด้านที่เกี่ยวกับ OOP เท่านั้น

Microsoft .NET Framework ถูกสร้างขึ้นบนแนวคิด OOP โดยสมบูรณ์ มันจะดูแลการสร้างและทำลาย object ให้แก่โค้ดที่ถูกเขียนขึ้นให้เข้ากับได้กับ .NET (.NET-enable code) โค้ดลักษณะนี้เรียกว่า managed-code (อ่านว่าแมนเนจด์ โค้ด หมายถึงโค้ดที่ถูกดูแลจัดการโดย .NET)

เนื่องจากภาษาและคอมไพลเลอร์เดิมใน Visual Studio 6 ไม่สามารถผลิต managed-code ได้ บริษัทไมโครซอฟท์จึงต้องประดิษฐ์ภาษาและคอมไพเลอร์ขึ้นใหม่ทั้งหมด ภาษา Visual Basic จึงกลายเป็น Visual Baisc.NET ภาษา Visual C++ จึงกลายเป็นภาษา Visual C++.NET และภาษา J++ จึงกลายเป็นภาษา Visual J# นอกจากนั้นบริษัทไมโครซอฟท์ยังประดิษฐ์ภาษาใหม่เพื่อให้เป็นภาษาพื้นเมือง (native language) ของ .NET คือภาษา C# ดังนั้นภาษา C# จึงเป็นเพียงภาษาเดียวที่ไมโครซอฟท์สร้างขึ้นเพื่อ .NET โดยตรง

ภาพ 116: บิลล์ เกสต์ ผู้ก่อตั้งบริษัทไมโครซอฟท์ (ภาพนี้ถ่ายในปี 1985)

.NET Framework และภาษา C# ของบริษัทไมโครซอฟท์เทียบได้กับ Java platform และภาษา Java ของบริษัทซัน ไมโครซิสเต็ม สอง framework นี้มีหลายๆ อย่างที่คล้ายกัน และมีหลายๆ อย่างที่แตกต่างกัน ยกตัวอย่างความคล้ายกันคือทั้ง .NET และ Java platform ทุกสิ่งทุกอย่างมาจาก object ยกตัวอย่างความแตกต่างกันคือ ใน .NET มีภาษาให้เลือกใช้มากกว่า 30 ภาษา ขณะที่ Java platform มีภาษาให้เลือกใช้เพียงเพียงภาษาเดียว (ภาษา Java)

ภาพ 117: เครื่องมืออำนวยความสะดวกเพื่อพัฒนาโปรแกรมภาษา Java (IDE) ชื่อ NetBeans

.NET Framework และภาษา C# เมื่อเทียบกับ Java platform และภาษา Java แล้ว .NET Framework และภาษา C# มีความก้าวหน้ากว่า แต่ไม่ใช่เรื่องน่าแปลกใจเพราะ Java เป็นเทคโนโลยีที่มีมาตั้งแต่ปี 1990 ส่วน .NET Framework และภาษา C# เกิดขึ้นภายหลัง Java นานถึงหนึ่งทศวรรษ

ต่อไปนี้เป็นคุณลักษณะเด่นบางประการของ .NET Framework ในแง่ OOP

1. ทุกสิ่งทุกอย่างใน .NET เป็น object: โปรดดูตัวอย่างการนิยามคลาสสองแบบต่อไปนี้

แบบที่ 1 นิยามคลาสตามปรกติ

class Foo()

{

}

แบบที่ 2 นิยามคลาสโดยสืบสันดานจากคลาส System.Object

class Foo(): System.Object

{

}

เมื่อคอมไพล์โค้ดทั้งสองแบบ จะได้ผลลัพธ์เหมือนกันทุกประการ เพราะตัวแปลภาษาของ .NET ถือว่าทุกคลาสสืบสันดานจากคลาส System.Object โดยปริยายอยู่แล้ว ด้วยเหตุนี้ทุก object จึงมี method พื้นฐานอยู่จำนวนหนึ่งโดยอัตโนมัติ (คือ Equals, GethashCode, GetType และ ToString คุณสมบัติเช่นนี้เหมือนกับ Java)

2. สนับสนุน encapsulation: ทุกภาษาใน .NET Framework สนับสนุนการสร้างคลาสและ struc โค้ดต่างๆ จะอยู่ภายในคลาสหรือ struc ทั้งหมด เช่น หน้าเว็บหนึ่งหน้าหรือหน้า Window หนึ่งหน้าจะเป็นคลาสๆ หนึ่ง ปฏิสัมพันธ์ระหว่างคลาสสามารถทำได้โดยผ่านกลไก property และ delegate

3. สนับสนุน Inheritance: ทุกภาษาใน .NET Framework สนับสนุนการทำ Inheritance อย่างเต็มที่ คลาสส่วนใหญ่ใน .NET Class Library เจตนาเขียนขึ้นให้นำไปใช้สืบสันดานได้ดี คลาสที่เราเขียนเองก็นำไปใช้เป็น base class ได้เช่นกัน การสืบสันดานจะทำกี่ชั้นก็ได้ แต่ทำได้จาก base class เดียว (single inheritance) หากต้องการสืบสันดานจากหลายคลาส (multiple inheritance) ให้ใช้วิธี interface แทน

4. สนับสนุน polymorphism: ทุกภาษาใน .NET Framework สนับสนุนการทำ method override, method overloading และ method hiding

5. ไม่มี Global method: ในโลกของการเขียนโปรแกรม .NET method ใดๆ ก็ตามต้องเป็นส่วนหนึ่งของคลาส ไม่มี method ที่เรียกใช้ได้อย่างลอยๆ โดยไม่มีที่มาที่ไป ดังนั้นท่านจะใช้เรียกใช้ method ใดก็ต้องเรียกผ่านคลาส โดยอาจนำคลาสมาสร้าง object เสียก่อนแล้วเรียกจาก object อีกที หรือจะเรียก method จากคลาสโดยตรง โดยไม่สร้าง object ก่อนก็ได้ (เรียกว่า static class) คุณสมบัตินี้เหมือนภาษา Java (ไม่เหมือนภาษา C++)

6. Object อยู่ใน heap: โปรแกรม .NET run-time จะสร้าง object ไว้ใน heap และทำลาย object เมื่อถึงวาระ มีบางกรณีเหมือนกันที่ object ไพล่ไปอยู่ใน stack (เรียกว่า value type) คุณจะได้เรียนรายละเอียดเรื่องนี้ในบทที่ 2 หัวข้อการจัดสรรหน่วยความจำ stack และ heap

7. สนับสนุนการทำ operator overloading: เช่นเดียวกับในภาษา C++ และภาษา Java ภาษา C# สนับสนุนการทำ operator overloading ซึ่งคือการเปลี่ยนหน้าที่ของตัวกระทำ (operator เช่น + – * ++ –) ให้ทำหน้าหน้าที่ใหม่ตามที่กำหนด เช่นเปลี่ยน operator + และ * เพื่อใช้กับเมทริกซ์เป็นต้น

นี่เป็นเพียงตัวอย่างบางประการของคุณลักษณะเด่นด้าน OOP ของ .NET Framework เมื่อท่านอ่านบทต่อๆ ไปท่านจะได้เรียนรู้รายละเอียดของคุณสมบัติเหล่านี้ คุณสมบัติอื่นๆ วิธีและประยุกต์ใช้งานโดยการสร้างโปรแกรมทีทำงานในเว็บ (web application)

สรุปท้ายบท

ความรู้พื้นฐานสามอย่างที่จำเป็นแก่นักเขียนโค้ดในอนาคตคือ OOP ภาษา C# และการเขียน web application ในบทนี้ผู้เขียนได้แนะนำ OOP ทางทฤษฏีอย่างเบื้องต้นอันเป็นข้อมูลที่จะช่วยให้ท่านอ่านบทต่อๆ ไปได้เข้าใจได้ง่ายขึ้น โดยเฉพาะ “คำจาร์กอน” ที่มีอยู่มากในวงการ OOP เป็นสิ่งสำคัญที่ท่านต้องเข้าใจความหมายจึงจะศึกษาในระดับที่ก้าวหน้าขึ้นได้ ในบทต่อไปท่านจะได้เรียนสิ่งสำคัญในการเขียนโปรแกรมภาษา C# นั่นคือเรื่องเกี่ยวกับ .NET Framework และคลาสไลบรารี

คำถามท้ายบท

1. object base programming แตกต่างกับ OOP หรือไม่ อย่างไร
2. อะไรคือ software component
3. encapsulation มีหลักการอย่างไร
4. inheritance มีหลักการอย่างไร
5. polymorphism มีหลักการอย่างไร
6. method overriding มีหลักการอย่างไร
7. method hiding มีหลักการอย่างไร
8. managed-code คืออะไร
9. อะไรคือสมาชิกแบบ data field
10. hierarchy คืออะไร

  เฉลยคำถาม

ตอนต่อไป: บทที่ 2 .NET Framework และคลาสไลบรารี

ตอน 6 : Polymorphism


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


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

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

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

 

 

Polymorphism

 

คำจาร์กอนของ OOP ที่ผู้คนหวาดกลัวมากที่สุดคือคำว่า polymorphism เพราะมันชวนให้นึกถึงยัญพิธีอันลี้ลับที่ hacker ประกอบในที่รโหฐาน แต่ตรงกันข้าม อันที่จริง polymorphism เป็นสิ่งเรียบง่ายที่แม้เด็กเล็กๆ ก็เข้าใจทุกคน

ท่านเคยเห็นเด็กเล่นดินน้ำมันหรือไม่ เด็กชอบดินน้ำมันเพราะนอกจากจะมีสีสันสวยงามแล้ว ยังนำมาปั้นให้เป็นรูปทรงอะไรก็ได้ตามใจชอบ คำว่า polymorphism (อ่านว่าโพลีมอร์ฟิส) มาจากคำในภาษากรีกสองคำ คือ poly (โพลี) แปลว่า หลาย และ morphism (มอร์ฟิส) แปลว่า รูปร่าง polymorphism จึงแปลว่า “หลายรูปทรง” หรือ “แปลงสภาพได้” เช่นเดียวกับดินน้ำมันที่เด็กๆ นำมาปั้นเป็นรูปทรงต่างๆ ได้หลายแบบ

ท่านอาจสงสัยว่าอะไรที่เปลี่ยนรูปร่างได้ และการเปลี่ยนรูปร่างได้มีประโยชน์อย่างไร คำตอบคือสิ่งที่เปลี่ยนรูปร่างได้คือ method ที่สืบสันดานมาจาก base class ประโยชน์คือช่วยให้เรานำคลาสมาใช้ได้โดยสามารถเปลี่ยนแปลง method บาง method ของ base class ให้ตรงกับความต้องการ (เรียกว่า method override) หรือสร้าง method ใหม่ทับของเดิมไปเลย (เรียกว่า method hiding)

ท่านจะเข้าใจหลักการ polymorphism เมื่อท่านเข้าใจการทำ method hiding และ method override ดังนั้นต่อไปนี้ผู้เขียนจะอธิบายสองเรื่องนี้ด้วยการยกตัวอย่างและแสดงโค้ด

 

method overriding

ยกตัวอย่างประโยชน์ของการทำ method overriding เช่น ผู้เขียนได้รับคลาสชื่อ CustomerData มาจากนายสมชาย นักเขียนโค้ดที่เป็นเพื่อร่วมงาน เป็นคลาสทำหน้าที่จัดการกับฐานข้อมูลลูกค้า คลาสนี้มี method อยู่ภายในจำนวนมาก ผู้เขียนใช้งานคลาสนี้มาหลายเดือนโดยไม่มีปัญหา

อยู่มาวันหนึ่งบริษัทโทรศัพท์ทั่วประเทศเพิ่มหมายเลขโทรศัพท์เป็น 12 หลัก ผู้เขียนพบว่าคลาส CustomerData ไม่สามารถรองรับการทำงานได้ จำเป็นต้องแก้ไขส่วน method ชื่อ CustomerPhone() ซึ่งทำหน้าที่จัดการหมายเลขโทรศัพท์ แต่ปัญหาคือนายสมชายได้ลาออกไปแล้ว ผู้เขียนไม่สามารถแก้ไข method CustomerPhone() ได้เพราะไม่มี source code

โชคดีที่นายสมชายเขียนคลาส CustomerData ไว้เป็น OOP โดยสมบูรณ์ ผู้เขียนจึงสามารถสร้างคลาสใหม่โดยสืบสันดานจากคลาสนี้ แล้วทำ method override โดยเขียนเฉพาะ method CustomerPhone() ขึ้นใหม่ ให้รองรับหมายเลขโทรศัพท์ 12 หลัก เนื่องจากผู้เขียนไม่เปลี่ยนแปลงวิธีเรียกใช้ method CustomerPhone()ผู้เขียนจึงไม่ต้องแก้ไขโค้ดภายนอกที่เรียกใช้ method นี้

 

หนังสือชื่อ Programming Microsoft Visual C# 2005: The base class libray สอนเทคนิคการนิยาม base class และ interface

 

method hiding

ต่อไปจะยกตัวอย่างประโยชน์ของการทำ method hiding คลาส CustomerData นี้มี method ชื่อ CleanAll() ทำหน้าที่ลบข้อมูลจากฐานข้อมูลทั้งหมด ผู้เขียนจะต้องมอบคลาสนี้ให้นักเขียนโค้ดผู้เป็นลูกทีมไว้ใช้งาน แต่ผู้เขียนไม่ต้องการให้ลูกทีมลบข้อมูลออกจากฐานข้อมูล ผู้เขียนจึงสร้างคลาสใหม่โดยสืบสันดานจากคลาส CustomerData แล้วทำ method hiding โดยการเขียนเฉพาะ method CleanAll() ขึ้นใหม่แต่ไม่ใส่โค้ดใดๆ ไว้ใน method ดังนั้นแม้ผู้นำคลาสนี้ไปใช้จะมองเห็น และเรียกใช้ method CleanAll() ได้ตามเดิม แต่จะไม่สามารถลบข้อมูลออกจากฐานข้อมูลได้

 

ต่อไปนี้คือตัวอย่างโปรแกรมของคลาส CustomerData โดยเขียนให้สั้นที่สุดเพื่อให้เข้าใจง่าย

 

class CustomerData
{
     protected virtual void CustomerPhone()
     {
          Console.WriteLine("02 123 456");
     }
     protected virtual void ClearAll()
     {
          Console.WriteLine("delete all data");
     }
}

 

เนื่องจากเป็นโค้ดตัวอย่าง ภายในคลาสจึงมีสมาชิกเพียงสอง method (ในคลาสจริงจะมีสมาชิกจำนวนมาก) ในแต่ละ method ทำงานเพียงแค่แสดงข้อความ (ในคลาสจริงจะมีโค้ดดำเนินการต่างๆ แทน)

ขอให้สังเกตว่า method CustomerPhone() ได้ถูกกำหนด modifier (อ่านว่า โมดิไฟร์เออร์ แปลว่าตัวแก้ไข ตัวดัดแปลง ในภาษา C# มีจำนวนมาก เช่น abstract, const, event, extern โปรดอ่านรายละเอียดในบทที่ 4 หัวข้อ type modifier) ให้เป็น virtual แสดงให้เห็นเจตนาของผู้เขียนโค้ด ที่ต้องการให้ผู้อื่นนำคลาสนี้ไปสืบสันดานเป็นคลาสใหม่ (คือนำไปใช้เป็น base class) และสามารถทำ override method นี้ได้ โปรดจำไว้ว่าในภาษา C# virtual และ override จะใช้คู่กัน

ต่อไปนี้เป็นตัวอย่างการสร้างคลาสใหม่โดยสืบสันดานจากคลาส คลาส CustomerData

 

1 class CustomerData2 : CustomerData
2 {
3      protected override void CustomerPhone()
4      {
5           base.CustomerPhone();
6           Console.WriteLine("02 123 456 7");
7      }
8      protected new virtual void ClearAll()
9      {
10     }
11 }

 

คลาสใหม่นี้ชื่อ CustomerData2 ผู้เขียนใช้สาทิตการทำ override และ hiding ไปพร้อมๆ กันในคลาสเดียว บรรทัดที่ 3 ถึง 7 คือตัวอย่างการทำ method override ซึ่งเป็นการเขียน method ใหม่ให้ทำงานแทน method ที่มี signature เดียวกันที่อยู่ใน base class (signature เหมือกันหมายถึงมี return type, method name และ parameter list ตรงกัน โปรดอ่านรายละเอียดเรื่อง method signature ในบทที่ 4)

ท่านคงสังเกตว่าในทั้งในคลาส CustomerData และคลาส CustomerData ต่างมี method ชื่อ CustomerPhone() ด้วยกันทั้งคู่ เนื่องจากคลาส CustomerData2 สืบสันดานจากคลาส CustomerData มันจึงรับมรดกสมาชิกทั้งหมดของคลาส CustomerData มาอยู่แล้ว การนิยาม method CustomerPhone()ในคลาส CustomerData2 ซ้ำอีกจึงเท่ากับทับการทำงานของ method CustomerPhone() ในคลาส CustomerData

คำสั่งบรรทัดที่ 5 เป็นเทคนิคที่น่าสนใจ นี่คือวิธีเรียกใช้ method CustomerData ตัวที่อยู่ใน base class ดังนั้นเมื่อ method CustomerData ของคลาส CustomerData2 ทำงาน method CustomerData ตัวที่อยู่ใน base class ก็จะทำงานด้วย เทคนิคนี้มีประโยชน์กรณีที่เราต้องการ override เพื่อเพิ่มเติมการทำงานของ method ใน base class

 

protected modifier

โปรดสังเกตว่า method CustomerPhone()ของคลาส CustomerData มี access modifier เป็น protected และมี type modifier เป็น virtual และ method CustomerPhone()ของคลาส CustomerData2 มี access modifier เป็น protected เช่นกันแต่มี type modifier เป็น override อันเป็นการใช้คู่กันอย่างที่เรียนให้ทราบไปแล้ว

การกำหนด access modifier ให้ method เป็น protected เป็นการแสดงเจตนาของผู้เขียนว่าต้องการให้ผู้นำคลาสนี้ไปใช้เป็น base class เพราะ method ที่เป็น protected จะถูกเข้าถึงได้จาก derived class เท่านั้น หากนำคลาสนี้ไปสร้าง object โค้ดภายนอกจะเรียกใช้ method นั้นไม่ได้

หากท่านไม่กำหนด method ของ base class ให้เป็น virtual แล้วพยายามทำ method override (ในคลาส CustomerData2) โปรแกรมจะคอมไพล์ไม่ผ่าน และคอมไพเลอร์จะแจ้ง error 0506 ซึ่งมีข้อความบอกว่า method นั้นๆ override ไม่ได้ สิ่งนี้ทำให้ภาษา C# แตกต่างจากภาษ Java เพระภาษา Java หากไม่ถูกกำหนด method สมาชิกจะเป็น virtual ไปโดยปริยาย แต่ภาษา C# จะเป็น non-virtual (คือไม่ใช่ virtual)

คำสั่งบรรทัด 8 ถึง 10 แสดงตัวอย่างการทำ method hiding โดยนิยามคลาส ClearAll() ขึ้นใหม่และใช้ modifier new เพื่อทับการทำงานของ method เดียวกันใน base class ด้วยการไม่ใส่คำสั่งใดๆ ในบล็อกของ method ทำให้แม้จะเรียกใช้ method ได้แต่ก็จะไม่มีการทำงานเกิดขึ้น

 

shadowing

การทำ hiding นอกจากจะทำกับ method แล้ว ยังสามารถทำกับสมาชิกอื่นๆ ของคลาส (เช่น field, property, event และ indexer เป็นต้น) ได้ด้วย ในภาษาอื่นๆ ของ .NET มีการทำ hiding ทั้งนั้นแต่อาจเรียกเป็นอย่างอื่น เช่นภาษา VB.NET เรียกว่า shadowing เป็นต้น

จะเห็นว่า hiding มีประโยชน์เมื่อเราต้องการปิดบัง หรือเพิกถอนการทำงานของสมาชิกบางตัวใน base class ทั้ง hiding และ overriding เป็นกลไกสำคัญที่ทำให้ภาษา C# มีความสามารถด้าน polymorphism ในบทหลังๆ ของหนังสือเล่มนี้ท่านจะได้เรียนวิธีประยุกต์หลักการ polymorphism กับการเขียนโปรแกรมสร้างเว็บไซต์โดยละเอียด

ที่ท่านได้อ่านมาทั้งหมดเป็นสามเสาหลักสำคัญของ OOP นั่นคือ encapsulation, inheritance และ polymorphism หากท่านเข้าใจสามเรื่องนี้ ก็ถือว่าท่านเข้าใจหลักการ OOP ทั้งหมด หากท่านอ่านทฤษฏีในบทนี้แล้วยังไม่เข้าใจ และยังไม่สามารถคิดเป็น OOP ก็ไม่ต้องเป็นกังวล เพราะเมื่อท่านอ่านอย่างถี่ถ้วนและทำแบบฝึกหัดในบทต่างๆ ของหนังสือเล่มนี้ครบหมด ท่านก็จะเข้าใจและสามารถคิดแบบ OOP ได้ในที่สุด

 

ตอนต่อไป: OOP กับ Microsoft .NET Framework

ตอน 5 : Inheritance


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

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

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

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

 

 

Inheritance

 

วิธีง่ายที่สุดเพื่อดูว่าภาษาใดเป็นภาษาที่สนับสนุน OOP หรือไม่ ให้ตรวจสอบว่าภาษานั้นสนับสนุน Inheritance หรือไม่ ถ้าไม่ แสดงว่าภาษานั้นไม่เป็น OOP

Inheritance (อ่านว่าอินเฮียริแตนซ์ แปลว่า “สืบสันดาน” หรือ “การสืบทอดมรดก”) เป็นหลักการสำคัญหนึ่งในสามหลักการของ OOP หลักการนี้ มีไว้เพื่อให้สามารถต่อยอดงานใหม่ จากงานเดิมที่เคยทำไว้แล้ว โดยไม่ต้องเริ่มจากศูนย์

ใน .NET Framework ทุกสิ่งทุกอย่างล้วนสืบสันดานจาก base class ชื่อ Object หรือกล่าวได้อีกอย่างหนึ่งว่าคลาสชื่อ Object เป็นต้นตระกูลของการการสืบวงศ์วานตามลำดับชั้น (เรียกว่า hierarchy อ่านว่า ไฮราคี แปลว่าลำดับชั้น) ยกตัวอย่างเช่นคลาส TextBox ซึ่งทำหน้าที่สร้าง object ที่เป็น WebControl แบบกล่องข้อความ มีลำดับการสืบสันดานดังนี้

 

System.Object

System.Web.UI.Control

System.Web.UI.WebControls.WebControl

System.Web.UI.WebControls.TextBox

 

จะเห็นว่า TextBox สืบสันดานจาก WebControl ซึ่งสืบสันดานจาก Control ซึ่งสืบสันดานจาก Object ดังนั้น TextBox จึงมี hierarchy เป็นอันดับสี่ในสายการสืบสันดานเมื่อนับจากต้นตระกูลหรือ root base class (ทั้งหมดอยู่ใน namespace System ดูรายละเอียดในบทที่ 2)

ภาพ 114: ระบบไฟล์ในฮาร์ดดิสก์เป็นตัวอย่างโครงสร้าง hierarchy

 

ยกตัวอย่างเช่น ท่านเขียนคลาสชื่อ ListProduct (หรือจะใช้ชื่ออะไรก็ตาม) เพื่อใช้สร้าง object ซึ่งทำหน้าที่แสดงข้อมูลรายละเอียดสินค้าหนึ่งชิ้น ไว้เมื่อสองเดือนก่อน พอถึงวันนี้ท่านต้องการ object ซึ่งทำหน้าที่แสดงข้อมูลรายละเอียดสินค้าสิบชิ้น แทนที่ท่านจะเขียนคลาสใหม่หมด หรือนำคลาส ListProduct มาแก้ไขใหม่ให้แสดงสินค้าสิบชิ้น (ซึ่งอาจทำไม่ได้ เพราะมีโปรแกรมส่วนอื่นใช้งานคลาสนี้อยู่) ท่านสามารถเขียนคลาสใหม่ชื่อ ListProductPage (หรือจะใช้ชื่ออะไรก็ตาม) แล้วดึงคุณสมบัติทั้งหมดของคลาส ListProduct มาไว้ในคลาสใหม่ และเพิ่มเติมคุณสมบัติใหม่เพื่อแสดงสินค้าเพิ่มอีกเก้าชิ้น

ในตัวอย่างย่อหน้าบนคลาส ListProduct ทำหน้าที่เป็น base class หรือ super class ส่วนคลาส ListProductPage ทำหน้าที่เป็น sub class หรือ derived class (child class ก็ว่า)

เพื่อให้ท่านเข้าใจหลักการ Inheritance มากขึ้น ผู้เขียนจะแสดงการเขียนโค้ดอย่างง่าย และสั้นที่สุด เพื่อสาทิตการหลักการ Inheritance โปรดพิจารณาคลาสต่อไปนี้

 

class Foo
{
     public void WriteFoo()
     {
          Console.WriteLine("Foo");
     }
}

 

นี่คือคลาสสั้นๆ ชื่อ Foo (ชื่อนี้ไม่มีความหมายพิเศษใดๆ) ภายในคลาสมีสมาชิกเพียงตัวเดียว คือ method ชื่อ WriteFoo() method นี้ทำหน้าที่พิมพ์คำว่า Foo บน ต่อไปผู้เขียนจะสร้างนิยามอีกคลาสหนึ่งที่สืบสันดานจากคลาสนี้

 

class Bar : Foo
{
     public void WriteBar()
     {
           Console.WriteLine("Bar ");
      }
}

 

โปรดสังเกตบรรทัดแรก class Bar : Foo ทำหน้าที่ประกาศชื่อคลาส (ชื่อ Bar) เครื่องหมายจุดคู่ (colon 🙂 ทำหน้าที่บอกให้รู้ว่าคลาสนี้สืบสันดานจากคลาสอื่น Foo คือชื่อของ base class

ภายในคลาส Bar มีสมาชิกเพียงตัวเดียว คือ method ชื่อ WriteBar ทำหน้าที่พิมพ์คำว่า Bar บนจอภาพ แม้ผู้เขียนจะนิยามสมาชิกไว้ในคลาส Bar เพียง method เดียว object ที่ถูกสร้างจากคลาส Bar จะมี method สอง method คือ WriteBar() และ method WriteFoo() ซึ่งเป็นมรดกจากคลาส Foo

โปรแกรมสำหรับทดสอบการทำงานของสองคลาสนี้เป็นดังนี้

 

1 static void Main(string[] args)
2 {
3      Foo myFoo = new Foo();
4      myFoo.WriteFoo();
5
6      Bar myBar = new Bar();
7      myBar.WriteBar();
8      Console.ReadLine();
9 }

 

โค้ดบรรทัดที่ 3 สร้าง object ชื่อ myFoo จากคลาส Foo บรรทัดที่ 4 เรียก method WriteFoo() ให้ทำงาน บรรทัดที่ 6 สร้าง object อีกตัวชื่อ myBar แล้วเรียกใช้ method WriteBar() ในบรรทัดที่ 7 ส่วนบรรทัดที่ 8 ทำหน้าที่หยุดรอการกดปุ่ม ถ้าไม่ใส่คำสั่งบรรทัดนี้ จะทำให้โปรแกรมจบการทำงานโดยเรามองผลลัพธ์ไม่ทัน

ผลลัพธ์จากการวิ่งโปรแกรมเป็นดังนี้

 

Foo

Bar

 

ในขณะที่ภาษา C++ สนับสนุนให้ sub class สืบสันดานจากหลายๆ base class ได้ (เรียกว่า multiple inheritance) แต่ภาษา C# กลับทำเช่นนั้นไม่ได้ เพราะภาษา C# และภาษา Java สนับสนุนให้ sub class สืบสันดานจาก base class ได้เพียงคลาสเดียวเท่านั้น (เรียกว่า single inheritance) บางคนเข้าใจผิดว่านั่นคือจุดด้อยของภาษา C# และ Java อันที่จริงแล้วผู้สร้างภาษาทั้งสองเจตนาที่จะตัด multiple inheritance ออกไปเพราะต้องการให้ภาษาของตนไม่ยุ่งยากซับซ้อน และได้ประดิษฐ์กลไกชื่อ interface (อินเตอร์เฟส อย่าสับสนกับ user interface หรือ hardware interface เพราะคนละเรื่องกัน) ขึ้นมาทดแทน ปัญหาใดก็ตามที่ต้องแก้ด้วย multiple inheritance จะสามารถใช้การทำ interface ทดแทนได้

ภาพ 115: James Gosling ผู้สร้างภาษา Java

 

ในหนังสือเล่มนี้ท่านจะได้เรียนทฤษฏี inheritance เพิ่มเติมในบทที่ 5 และเรียนภาคปฏิบัติโดยละเอียดในบทที่ 7

 

ตอนต่อไป : Polymorphism