Reflection #2 : Assembly

    ในบทที่แล้ว เราเรียนรู้กันเรื่องการดูรายละเอียดเกี่ยวกับ Type ต่างๆ ในบทนี้เราจะมาแอบดูกันต่อว่า Type ต่างๆ ที่เราใช้กันอยู่ทุกวันนี้ ล้วนแล้วแต่ต้องมี physical ในการเก็บทั้งสิ้น และ physical นี้ก็คือแฟ้มข้อมูล .dll ที่เราเรียกกันว่า Assembly นั่นเอง แต่ก่อนที่เราจะเรียนรู้กันต่อ ผมขอแทรกอะไรหน่อยก่อน จะได้รู้ที่มา

แนวคิดของ Reflection

    Reflection เป็นแนวคิดที่มีมานานแล้ว แนวคิดหลักของการทำ Reflection ก็คือการเก็บโครงสร้างของ Type ต่างๆ แยกออกมาต่างหาก ซึ่งโครงสร้างเหล่านี้ เราเรียกว่า Metadata นั่นเอง แนวคิดของการแยก Metadata ออกมาต่างหากนั้น มีมานานแล้ว เท่าที่ผมสามารถไล่ย้อนไปได้ ก็น่าจะตั้งแต่ภาษา CLOS (Lisp version ที่เป็น OO) ภาษา C++ ไม่มีแนวคิด Reflection ในตัว ต้องหาบริการเสริมกันให้วุ่น ภาษาที่ใช้แนวคิด Reflection แล้วรุ่งก็คือภาษาตระกูล Visual ของ Microsoft และ Java ทั้งนี้ก็ใช้บริการของ COM และ CORBA นั่นเอง

    ในเมื่อ COM มี Reflection จึงไม่น่าแปลกใจเลยว่า .NET ก็ต้องมี แต่คุณอาจจะสงสัยว่าประโยชน์ที่แท้จริงของ Reflection มันคือการที่ให้ Editor มีความสามารถทำ IntelliSense อย่างที่ผมเขียนในบทที่แล้วหรือ เปล่าเลยครับ นั่นคือผลพลอยได้ที่ทีมพัฒนาของ Microsoft ประยุกต์ใช้ แต่แท้ที่จริงแล้วประโยชน์ของ Reflection มันอยู่ที่คำว่า Persistent ครับ

 

Persistent

    Persistent คืออะไร คำนี้ผมสงสัยมานานแล้วเหมือนกัน คำนี้โผล่มาตอนแรกๆ ที่ผมหัดเขียนภาษา Progress และโผล่มาอีกทีเมื่อผมอ่านหนังสือ Object-Oriented Analysis and Design ของ ปรมาจารย์ Grady Booch ในหนังสือกล่าวไว้ว่า Persistent คือการที่ object สามารถถูกเก็บออกจาก Memory Space ที่มันอยู่ ผมเลยไปตีความเอาว่า คงจะประมาณว่า โปรแกรมรันอยู่ อาจจะมีความจำเป็นต้องปิดเครื่อง เราเลยต้องเอา objects ทุกตัวที่ทำงานอยู่ ไปเก็บพักใน harddisk พอพรุ่งนี้เช้า ค่อย Load มันออกมา มันจะได้ทำงานต่อจากเมื่อวานได้เลย ไม่ต้องเริ่มที่ 0 ใหม่

    แบบนี้มีจริงๆ นะครับ มันเป็นเรื่อง Object Database Model ที่ทาง OMG พยายามจะปั้นอยู่ตอนนี้ Object Database เป็นแนวคิดที่ไม่ได้ใหม่นัก แต่ก็ถือว่าเป็นของใหม่ล่าสุด เพราะยังไม่มีคนใช้ แต่ต่อไป คงจะนิยมมาก มันแตกต่างจาก Relational Database ที่เราใช้ทุกวันนี้ค่อนข้างมาก ถ้าใช้เป็น เราจะได้ความสะดวกและประสิทธิภาพสูง แนวคิดของ Object Database ก็เป็นเหมือนที่ผมเข้าใจเข้า มันจะเก็บ Object แบบ Persistent นั่นเอง

    เวลาเราเก็บ Object ลง Database นั้น ถ้าเราไม่เก็บ MetaDatabase ลงไปด้วย ข้อมูลที่เก็บก็จะเป็นเพียงแค่ขยะ พรุ่งนี้เช้ามาดึง object ก็จะไม่รู้ว่า Object ดังกล่าวมีหน้าตาอย่างไร จึงจำเป็นอยู่เองครับที่ต้องมีแนวคิด Reflection อยู่

N-tier

    คราวนี้ถ้าผมตีความคำของ Booch ใหม่ว่าการเอาออกจาก Memory Space ที่มันใช้งานอยู่ ไม่ได้เอาไปเก็บ แต่เอาไปรันที่ Memory Space อื่น เริ่มคุ้นแล้วใช้ไหมครับ มันก็คือแนวคิด N-tier ที่เราใช้อยู่ทุกวันนี้ทั้งในองค์กรและ Internet นั่นเอง เราสามารถเก็บ Object ไว้ที่เครื่องอื่น เวลาเราเรียกใช้ ขอให้เรารู้โครงสร้างของมัน เราก็สามารถเรียกใช้ได้เลย ถ้าจะเอาเป็นของใหม่ ก็เรื่อง Web Service มันมีการส่ง Metadata ออกมาให้เครื่อง Client ใช้เรียก ถ้าพูดอีกมุมหนึ่ง ก็พอจะบอกได้ว่า WSDL เป็น protocol ที่เอาไว้ส่งผ่าน Metadata ระหว่างเครื่องนั่นเอง

   

Assembly

    มาเข้าเรื่องของเราซักที ในอดีตของ Microsoft ตัว COM นั้นเก็บเฉพาะข้อมูล และ code ไม่มี Metadata ดังนั้นเพื่อให้รองรับแนวคิดของ Reflection ตัว COM จึงต้องเก็บ Metadata แยกต่างหากเป็นอีกแฟ้มข้อมูลหนึ่ง แต่พอมาเป็น .NET ทั้ง code และ Metadata อยู่ในแฟ้มเดียวกัน คือ .dll เลยครับ เรามาลองดู ผลลัพธ์ที่ผมแอบดู Assembly System.dll ดังนี้ครับ

   

    จากรูปนี้เราจะเห็นได้ว่า ใน Assembly จะมีส่วนหนึ่งที่ชื่อว่า Manifest ซึ่งนั่นก็คือส่วนของ Metadata นั่นเอง Assembly ของ .NET จึงถือว่ามีความสมบูรณ์ในตัว ถ้าเราส่งผ่าน Internet ทำนอง Applet ผู้ใช้จะสามารถรู้โครงสร้างทั้งหมดได้ทันที ไม่ต้องพึ่งแฟ้มอื่นอีก

 

แอบดู Assembly

    ในส่วนสุดท้ายเรามาแอบดู Assembly กัน ผมคงไม่อธิบายอะไรมากนัก เพราะคุณสามารถเปิด Help ได้อยู่แล้ว

ShowTypes.cs

using System;
using System.Reflection;
class ShowTypes
{ 	
	public static void ShowTypes()
	{

Assembly ass = Assembly.Load("system");
Console.WriteLine(ass.FullName);
foreach( Type t in ass.GetTypes()) {
   Console.WriteLine(t.FullName);
}

	}
	public static void Main()
	{
		ShowMethods();
	}
}

โปรแกรมนี้แสดง Types ทั้งหมดของ System.dll ดังนี้ครับ

DOS Prompt

C:\CS> ShowTypes

System.Diagnostics.Trace
System.Collections.Specialized.ListDictionary
System.Collections.Specialized.ListDictionary+NodeEnumerator
System.Collections.Specialized.ListDictionary+NodeKeyValueCollection
System.Collections.Specialized.ListDictionary+NodeKeyValueCollection+NodeKeyVal
eEnumerator
System.Collections.Specialized.ListDictionary+DictionaryNode
System.Diagnostics.EventLogTraceListener
System.ComponentModel.IContainer
System.ComponentModel.Design.Serialization.IDesignerSerializationService
System.CodeDom.CodeComment
System.Net.BasicClient
System.Net.Sockets.SocketOptionName
System.ComponentModel.Design.IExtenderListService
Microsoft.Win32.PowerModeChangedEventHandler
System.Net.Dns
System.Net.Dns+GetHostByNameDelegate
System.Net.Dns+ResolveDelegate
System.ComponentModel.Design.DesignerTransaction
System.IO.FileSystemWatcher
System.IO.Direct
System.ComponentModel.DefaultEventAttribute
System.Text.RegularExpressions.RegexParser
System.ComponentModel.LocalizableAttribute
System.ComponentModel.UInt16Converter
....


C:\CS>_

       ในแต่ละบรรทัดที่เรา foreach() เราจะได้ type มา ตัวหนึ่ง เราสามารถที่ใช้ ShowMethods() ของบทที่แล้วมาแสดงรายละเอียดของแต่ละ Type ลองอ่าน Code ดูนะครับ ไม่น่าจะมีอะไรเข้าใจยาก

Reflection

    ถ้าใครสนใจรายละเอียดว่า เขาทำ Reflection กันอย่างไร คุณสามารถศึกษาเพิ่มเติมได้ ที่หนังสือ Pattern Languages of Program Design 2 ของ Vlissides และ Coplien จะมีบทหนึ่งที่เกี่ยวกับ Pattern ของการทำ Reflection อ่านกันเต็มอิ่มเลยครับ  (Vlissides เป็นหนึ่งใน Gang of Four ที่เขียนหนังสือ Design Pattern อันโด่งดังครับ)