Namespace

    ทุกคนเมื่อมาอ่านหน้านี้แล้วต้องเคยใช้ Namespace มาก่อนแล้วทั้งนั้น แต่จะรู้ตัวหรือไม่ก็เป็นอีกเรื่องหนึ่ง ส่วนของ Namespace ที่เราระบุนั้น ก็เป็นส่วนของคำสั่ง using นั่นเอง ยกตัวอย่างเช่น

using System;
using System.Windows.Forms;

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

System.Windows.Forms.Form form1 = new System.Windows.Forms.Form();

ถ้าเราใช้ using แบบข้างบนเราสามารถเขียนใหม่ได้ดังนี้ครับ

Form form1 = new Form();

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

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

ทำไมการเรียกใช้งาน class ถึงต้องมีจุดจุดลงไปหลายชั้น?

    คุณอาจสงสัยปัญหานี้ว่าทำไม .NET Framework ถึงไม่ออกแบบให้เราสามารถเรียกใช้งานได้โดยตรงต้องเรียกผ่านหลายๆ ชั้นแบบนี้ (การเรียกผ่านชื่อยาวๆ แบบนี้เราเรียกว่า full qualified) เรื่องนี้เข้าใจได้โดยไม่ยากครับ Libray ของ .NET Framework นั้นมีขนาดใหญ่มาก ใหญ่ที่สุดเท่าที่ Microsoft เคยสร้างมา ครอบคลุมเนื้อหาค่อนข้างจะครบถ้วน และด้วยความใหญ่นี่เองทำให้เราไม่สามารถเรียกใช้งานแบบชั้นเดียวได้ เราต้องย่อยลงไปหลายๆ ชั้น มองภาพเป็น Hierarchy นั่นเอง เราเรียกโครงสร้างของ class ที่แบ่งเป็นชั้นๆ นี้ว่า Namespace

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

    มีสิ่งหนึ่งที่ควรจะกล่าวถึงหน่อย คือถ้าใครมาจากภาษา Java จะต้องทำความเข้าใจใหม่นะครับ เพราะแนวคิดไม่เหมือนกันทีเดียว ในภาษา Java นั้นมีการสร้างลักษณะคล้ายกับ Namespace เหมือนกัน แต่สิ่งที่ Java ทำนั้น จะเอา class แต่ละ class นั้นไปเก็บเป็น file และ file เหล่านี้จะเก็บตามโครงสร้าง Directory ของ OS ซึ่งอาจกล่าวได้ว่า Namespace ของ Java นั้นสร้างจาก Directory แต่การกระทำอย่างนี้มีจุดอ่อนนะครับ เพราะถ้าพึ่งกับ Directory มากๆ แบบนี้ทำให้แฟ้มข้อมูล 1 ตัวสามารถรองรับ class ได้เพียง 1 class เท่านั้น แต่เหตุการณ์นี้ไม่เกิดกับ .NET Framework ครับ เพราะการกำหนด namespace นั้นเป็นเรื่องทาง Logical ครับ ไม่ได้เป็นตัวกำหนดการเก็บจริงๆ .NET Framework เก็บ code ที่ compiled แล้วไว้ในสิ่งที่เรียกว่า Assembly ซึ่งเราจะได้เรียนรู้ในบทต่อๆ ไปครับ

ในเมื่อไม่ได้ใช้ Directory เป็นโครงสร้างในการเก็บ .NET Framework มีวิธีระบุสถานที่เก็บ class ได้อย่างไร?

    คงต้องเน้นเหมือนเดิมว่าเรื่อง namespace นั้นเป็นเรื่อง logical ไม่ได้ผูกกับ directory ภาษา C# นั้น source code แฟ้มเดียวสามารถสร้างได้หลาย namespace ลองดู Code นี้ครับ

namespace.cs

using System;
namespace xyz
{
	using twoguru.lib;
	class Start {
		public static void Main()
		{
			SayHello hello = new SayHello();
			hello.SayIt();
		}
	}
}
namespace twoguru.lib
{
	class SayHello
	{
		public void SayIt()
		{
			Console.WriteLine("Hello, World");
		}
	}
}	

    จากโปรแกรมนี้คุณจะเห็นได้ว่าในแฟ้มเดียวนี้เรามี 2 namespace คือ xyz และ twoguru.lib โดยการใช้ namespace { } ในการคร่อม class ที่เราต้องการ เมื่อเวลาที่เราเรียกใช้ twoguru.lib จาก  xyz เราควรจะใช้ using เพื่อให้ใช้งานได้สะดวกขึ้น

    แล้วโปรแกรมที่เราเขียนมาหลายบทนี้ไม่เคยมี namespace ถามว่ามันอยู่นอก namespace ใช่หรือไม่ คำตอบคือไม่ใช่นะครับ ถ้าเราไม่กำหนด namespace ในโปรแกรม ทางภาษา C# จะแอบเอา class ต่างๆ ของเราไปเก็บไว้ใน default namespace ครับ

    ยิ่งไปกว่านั้นนะครับ ไม่ใช่ว่าแฟ้ม namespace.cs นี้เท่านั้นนะครับ ที่สามารถสร้าง class สำหรับ namespace twoguru.lib หรือ xyz แฟ้มอื่นก็ได้เหมือนกัน เพียงแค่เราคร่อมด้วยคำสั่ง namespace xyz หรือ namespace twoguru.lib มันจะเอาไปรวมกันได้เลยครับ

ถ้าสองบริษัทตั้งชื่อ class เหมือนกันเราต้องใช้วิธีการเขียนยาวๆ (full qualified) เสมอใช่หรือไม่?

กรณีปัญหา: สมมุติว่าเรามี class อยู่ 2 ตัวชื่อว่า PictureButton มาจาก 2 บริษัทคือ Farpoint และ ComponentOne โดยที่

    FarPoint ใช้ namespace ว่า  FarPoint.ProSuite
    ComponentOne ใช้ namespace ว่า ComponentOne.Apex.TrueInput

ถ้าเราจำเป็นต้องใช้ปุ่มทั้งสองแบบในโปรแกรมเดียวกันเราใช้

using FarPoint.ProSuite.PictureButton;
using ComponentOne.Apex.TrueInput;

ดังนั้นถ้าเราเรียกใช้ PictureButton มันจะหมายถึงของ FarPoint เสมอ ทางออกทางหนึ่งถ้าเราสร้าง object ปุ่มของ ComponentOne เราต้องใช้วิธี full qualified แต่นั้นไม่ใช้วิธีที่ดี เรามีทางออกโดยการใช้ alias กับ namespace ได้ครับ

using FP = FarPoint.ProSuite.PictureButton;
using  CO = ComponentOne.Apex.TrueInput;

ดังนั้นถ้าเราต้องการสร้างปุ่มเราสามารถเขียนได้ดังนี้ครับ

FP.PictureButton  b1 = new FP.PictureButton();
CO.PictureButton b2 = new CO.PictureButton();