Archive

Archive for October, 2008

XML Schema ความเข้าใจเกี่ยวกับ namespace

October 26, 2008 5 comments

จากข้อกำหนด ของ W3C  Namespace in recommendation  XML Namspeces คือกลุ่มขอล elements และ attributes ที่เป็นไปตามข้อกำหนด IRI – กลุ่มของ elements และ attributes เหล่านี้เราเรียกกว่า  XML vocabulary ครับ  สิ่งสำคัญเลยที่ทำให้ต้องมี Namespace ก็คือการหลีกเลี่ยง naming conflicts เมื่อมีการ สร้าง XML documents และมีการ เรียกใช้หลาย ๆ ที่ หรือ เรียกใช้ Vocabularies หลาย ๆ ที่  ตัวที่ต้องใช้งาน Namespace มาก ๆ ก็คือ XML schema ซึ่ง XML schema นี้เราใช้สำหรับการกำหนด vocabulary หรือ โครงสร้างของ XML ที่เราต้องการใช้งาน แฮะ แฮะ ไม่ทราบว่าจะ get หรือปล่าว  ( เราอาจจะต้องเข้าใจ XML schema และ ก็ concept ต่าง ๆ ด้วย )

Namespace ก็มีลักษณะคล้ายกับ packages ใน Java หรือ  namespace ใน C# ครับ

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

  • หน้าที่ ของ XML
  • การประกาศ ( declare ) และการใช้งาน namspaces
  • ความแตกต่างระหว่าง default-namespace และ no-namespace
  • การสร้าง Namespaces โดยใช่ XML schema และ
  • ความแตกต่างกันระหว่าง qualified และ unqualified element/attributes

การประกาศ และ การประยุกต์ใช้

Namespaces นั้นเราประกาศใน attribute ของ XML element ครับ  และก็ไม่จำเป็นว่าเราจะต้องประกาศ มันไว้ที่ root element มันสามารถที่จะประกาศไว้ใน element ใด ๆ ก็ได้ใน XML document. นั่นก็หมายความว่า มันต้องมี scope นะสิครับ  scope ของ namespace ก็ จะอยู่ภายใต้ที่ element ที่ namespace นั้นถูกประกาศครับ เริ่มตั้งแต่ opening-tag ไปจนถึง ending-tag ของ element

การประกาศ Namespace ทำดังนี้นะครับ

<someElement xmlns:pfx=”http://www.Teerapong.com”/&gt;

จากตัวอย่างจะเห็นว่า xmlns ก็คือ attribute ของ someElement นะครับ มันใช้สำหรับการ ประกาศ namespace ซึ่งชื่อของ namespace ก็คือ http://www.Teerapong.com  และ เจ้า xmlns นี้นอกจากจะประกาศ namespace แล้วยังก็หนด aliase หรือ prefix สำหรับการใช้งานอ้าง อิง namespace นี้ด้วย ฝรั่งเขาใช้คำว่า binding นะครับเวลาอ้างอิง namespace นี้ทีไหนก็ตาม ก็ใช้เฉพาะั ตัว alias หรือ prefix เท่านั้นนะครับ พอเข้าใจนะครับ อย่างเช่น เมื่อเราสร้าง XSD schema เราประกาศ แบบนี้

<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; .. />

หลังจากนี้เมื่อเราต้องอางอิง element หรือ types ต่าง ๆ เราก็ prefix ด้วย xsd ด้วยเสมอ แม่นบ่ครับ ไม่เช่นนั้นมันก็จะฟ้อง error ต่อว่าเราว่า ไม่มี element หรือ ไม่มี type ที่กำหนด ไว้ใน http://www.w3.org/2001/XMLSchema

อันที่จริงแล้ว prefix หรือ aliase นั้นเราจะกำหนดเป็นอะไรก็ได้นะครับ ผมรู้ว่ามีคำถามนี้อยู่ในใจ เราสามารถกำหนดให้เป็นอะไรก็ได้ตามใจท่านนะครับ แต่ก็ต้องไม่ลืมนะครับ ว่าต้องให้มันสื่อความหมายด้วยไม่เช่นนั้น ปัญหาผมร่วงจะมาสู่ท่านภายหลัง นะครับ software engineer เข้าเรียกว่า meaningful นะครับ

ยังมีอีก คำถาม หนึ่งมั้ง บางคนเข้าใจว่ามันจะต้องอ้างอิงไป URL หรือป่าวเห็นประกาศเป็น URL คำตอบก็คือไม่ใช่นะครับ เราจะกำหนดให้มันเป็นอะไรก็ได้ ไม่จำเป็นต้องเป็น URL ก็ได้ เนื่องจากว่า namespace นั้นใช้สำหรับการกำหนด virtual container สำหรับที่เราจะ group XML ไว้เป็นกลุ่ม ๆ ให้ง่ายต่อการอ้างอิงใช้งาน ครับ ที่เขา URL ก็เพราะว่ามันน่าจะ unique การที่จะมีการกำหนดซ้ำกันก็คงเกิดขึ้นได้น้อย ครับ

คุณอยากจะกำหนดแบบนี้ก็ได้

<someElement xmlns:pfx=”Teerapong” />

ซึ่งก็ไม่ได้ผิดกฏ หรือ ข้อกำหนดใด ๆ แต่ก็ควรให้เป็นไปตาม W3C Namespace in XML Recommendation ก็จะดี….

ครับถึงนี่แล้วก็คงจะพอเข้าใจนะครับ การใช้ namespace อันดับแรก เราจะ bind เข้ากับ aliase หรือ prefix เสร็จแล้วเวลาอ้างอิงเราก็ใช้ aliase หรือ prefix ในการอ้างอิง namespace ผมคิดว่าก็คงจะมีข้อสงสัยตามมาอีกว่าทำไมถึงไม่ใช้ namespace อ้างอิงตรง ๆ เลยหล่ะเหตุผล ก็คือ namespace ที่เรากำหนด ตาม recommendation นั้นมันจะยาวววว และที่สำคัญก็คือมันอาจจะส่งผลกระทบอัน ใหญ่หลวงกับ syntax ของ XML ก็ได้เพราะว่า มันจะมี characters ที่ไม่อนุญาตุให้ใช้ใน tags ไงครับ  🙂

<http://www.library.com:Book /> ผิด

<lib:Book xmlns:lib=”http://www.library.com”/&gt; ถูกต้อง

ดูตัวอย่าง เต็ม อีกนิด

<?xml version="1.0"?>
<Book xmlns:lib="http://www.library.com">
	<lib:Title> Sherlock Holmes</lib:Title>
	<lib:Author>Arthur Conan Doyle</lib:Author>
</Book>

อีกตัวอย่างนะครับ

<?xml version="1.0"?>
<Book xmlns:lib="http://www.library.com">
	<lib:Title>Sherlock Holmes - I</lib:Title>
	<lib:Author>Arthur Conan Doyle</lib:Author>
   <Purchase xmlns:lib="http://www.otherlibrary.com">
	<lib:Title>Sherlock Holmes - II</lib:Title>
	<lib:Author>Arthur Conan Doyle</lib:Author>
   </Purchase>
	<lib:Title>Sherlock Holmes - III</lib:Title>
	<lib:Author>Arthur Conan Doyle</lib:Author>
</Book>

ตัวอย่างนี้ จะให้เห็น ในเรื่อง scope นะครับ สังเกตุดูจะเห็นว่ามี 2 namespace ซึ่งประกาศใน Book และ purchase contentของทั้ง แม้จะกำหนด ให้มี prefix เหมือนกันก็ตาม content ของ purchase จะอ้างอิงกับ http://www.otherlibrary.com ส่วน content ของ Book จะ อ้างอิงไปยัง http://www.library.com ดังนั้น element  Title และ Author ของ Cherlock Holmes I กับ Title และ Author ของ Cherlock Holmes III จะอ้างอิงที่ namespace เดียวกัน 🙂

Default-namespace และ  No-namespace

บ้างครั้งการทำงานก็มักจะเกิเอาการขี้เกียจขึ้น บ้างท่านก็ไม่อยากจะพิมพ์ prefix หรือ aliase นำหน้า element หรือ attribute ทุกครั้ง ๆ  ในกรณีนี้ นะครับ เราสามารถที่จะใช้ default namespace แทนนะครับ แต่ต้องจำไว้นะครับ ว่าเราจะประกาศ default namespace ได้ที่ namespace เดียวนะครับ  ไม่เช่นนั้นก็จะนำซึ่งปัญหา ผมร่วงได้นะครับ

การประกาศ default namespace นี้จะทำให้ element ใดก็ตามที่อยู่ใน scope ของ default namespace นั้น จะอ้างอิงไปยัง namespace นั้นอย่างอัตโนมัติ เขาใช้ำว่า implicitly qualifies นะครับ ( ในกรณีที่เราไม่ได้กำหนด prefix ใดใด นะครับ ก็คือ ไม่ได้ explicitly qualifies ) ใช้ technical term เยอะ ก็จะงงนะครับ แต่ผ๊มมมว่า มันได้ใจความดีกว่าใช้ภาษาไทยนะครับ อย่า บ่น ผมเลยย ดูการประกาศดีกว่า


<?xml version="1.0"?>
<Book xmlns="http://www.library.com">
   <Title>Sherlock Holmes</Title>
   <Author> Arthur Conan Doyle</Author>
</Book>

ครับ นี่แหละครับ default namspace ประกาศดังนี้ทำให้เราไม่ต้อง ใส่ prefix ให้กับ element ภายใต้ scope ของ element ที่ declare  default namespace นะครับ เช่นเดียวกันนะครับ ถ้าผมยกตัวอย่างเดิมดังนี้

 <?xml version="1.0"?>
<Book xmlns="http://www.library.com">
   <Title>Sherlock Holmes - I</Title>
   <Author>Arthur Conan Doyle</Author>
   <Purchase xmlns="http://www.otherlibrary.com">
      <Title>Sherlock Holmes - II</Title>
      <Author>Arthur Conan Doyle</Author>
   </Purchase>
   <Title>Sherlock Holmes - III</Title>
   <Author>Arthur Conan Doyle</Author>
</Book>

ครับก็ ความหมายเหมือนกับ ตัวอย่างที่แล้วนะครับ scope ใครก็ scope มันนะครับ ถึงแม้จะไม่มี prefix ก็ตาม 🙂

Default Namespace และ Attribute

มันก็แปลก ๆ เล็กน้อยสำหรับ attribute กับเรื่อง Default Namespace  ไม่สามารถใช้กันได้ เป็นงั้นซะอีก นะครับ ดังนั้นการที่จะให้ attribute มันสามารถอ้างอิงไปยัง namespace ได้ก็ต้อง explicitly qualified นะครับ  สมมุติว่า element Book มี attribute ชื่อว่า isbn เราจะต้องประกาศแบบนี้นะครับ


<?xml version="1.0"?>

<Book  pfx:isbn="1234"
            xmlns="http://www.library.com"
            xmlns:pfx="http://www.library.com">
    <Title>Cherlock Holmes</Title>
    <Author>Arthur Conan Doyle</Author>
</Book>

วันนี้ต้อง หยุดไว้แค่นี้ก่อนะครับ แล้วจะมาต่อ ให้จบนะครับ

Common Language Infrastructure ( CLI ) ภาคเกริ่นนำ

October 14, 2008 2 comments

อืม เห็นขึ้นต้นอย่างนี้ ไม่มีอะไรแปลกหรอก ครับ พอดีมีเรื่องอยาก เขียน คือเรื่องของ Mono-project หลายคนเห็นชื่อนี้คงนึกออก หลายห่านไม่รู้จักหลายท่านบอกว่าคุ้น ๆ หู  แต่ก่อนที่จะไปเรื่อง Mono-project ผมก็คงจะต้องกล่าวถึง Common Language Infrastructure กันเสียก่อน เป็นข้อมูลพื้นฐานและเข้าใจว่า Mono-project เป็นมาอย่างไร นะครับ 🙂

ก็อย่างที่ได้เกรินนำไปนั้นแหละครับ เรามาพูดกันถึงเรื่อง Common Language Infrastructure หรือ CLI กันว่ามันเป็นอย่าไร ทำไมต้องรู้จักมัน และมันเกี่ยวกับ .NET อย่างไร

CLI เป็นข้อกำหนดหรือ specification ที่ทาง Microsoft เขาได้พัฒาขึ้นมา ซึ่งก็เป็น ตัว .NET Technology ของเขาเองนั้นแหละครับ (ปัจจุบันเป็นมาตรฐาน ECMA-335) ที่จะทำให้ application ที่ถูกพัฒนาจาก high level programming language ต่าง ๆ สามารถทำงานได้ บนระบบที่มี environment ต่าง กันได้ หรือ กล่าว ง่าย ๆ ก็คือสามารถทำงานบน platform ต่าง ๆ กันได้โดยเป็น ลักษณะ Platform independent นั่นเองครับ

อันที่จริง  Java เขานำไปแล้วครับ แต่ว่า .NET กำลังมาตอนนี้ แต่ที่แรงกว่า Java คือ มันสามารถเขียนได้ด้วยภาษาต่าง ๆ ได้ ที่ compatible หรือ ภาษาที่ทำตาม specification ที่ CLI กำหนด หรือ เอาตามมาตรฐาน EMCA-335 นั่นเอง ซึ่งมันมีเยอะ นะครับ นอกจาก ของ Microsoft เองแล้วยังมีภาษาอื่น อีกหลายภาษา ผมเอง ก็จำไม่ได้ว่ามี ภาษาอะไรบ้างที่พอจำได้ก็อย่างเช่น COBOL เป็นต้น
CLI specification หรือ ข้อกำหนด CLI  มีหลัก ๆ อยู่ 4 เรื่อง [Wikipedia – Common languague Infrastructure]

คือ

  • Common Type System (CTS) เกี่ยวกับ type และ operations ที่ CTS-compliant(ภาษาต่าง ๆ) ใช้ร่วมกัน  CTS ถือว่าเป็นหัวใจสำคัญ ของ CLI เลยหล่ะครับ
  • Metadata ก็คือข้อมูลต่างๆ ของโปรแกรม ซึ่ง CLI ใช้ในการอธิบายและอ้างอิง types ต่าง ๆที่ กำหนดใน CTS  และ มันก็จะถูกผนวกเขาใน assemblies ในระหว่างที่ทำการ compilation
  • Common Language Specification (CLS) เป็นกฏพื้นฐาน ภาษาต่าง ๆ จะต้องทำตาม เพื่อที่ภาษาเหล่านี้จะสามารถทำงาน ด้วยกันได้ (ภาษาที่ว่านี้ ก็คือภาษาที่ทำตาม specification ของ CLI นะครับ หรืออาจจะเรียกว่า CLI language ก็ได้เนอะ ) เพราะฉะนั้น module ที่เขียนจากภาษาหนึ่ง ก็สามารถถูกอ้างอิงหรือ เรียกใช้จากอีกภาษาหนึ่งได้ ว่างั้น
  • Virtual Execution System (VES) เมื่อ ภาษาเหล่านั้น compile และได้ managed code ออกมา VES จะเป็นตัว execute ซึ่งก็ใช้ข้อมูลต่าง ๆ ที่ฝังมาด้วย ( meta data )


ภาษาต่าง ๆ ( CLI language ) หลังจาก compile code ของตัวเอง แล้วจะได้  intermediate language หรือ Common Intermediate Language ( CIL ) หรือ managed code นั้นและเนอะ ซึ่งมันยังไม่หยั่งลงไปถึง platform hardware คือมันยังมองผ่าน abstract อยู่นะครับ  ถัดมา  VES จะเป็นตัว compile CIL ต่อโดย ทำงานร่วมกับJIT  แปลง code เหล่านั้นให้สามารถทำงาน ได้ กับ hardware ที่มันทำงานอยู่ นะสิ ก้คือ ได้ machine language ที่ทำงานกับ hardware นั้น ๆ อืมก็ประมาณนี้แหละ อ่าว แล้วไงหล่ะครับพูดไปพูดมา Common Language Runtime ( CLR ) หายไปไหน หว่า อันที่จริงไม่ได้หายไปไหนหรอก เพราะมันก็คือ environment ที่ VES และ JIT ทำงาน อยู่ นั้นแหละ ครับ 🙂

คราวนี้ตามมาอีกสักนิดนะครับ หลังจากนี้มันก็จะก้าวไปสู่ Cross Platform นะสิครับ  ตราบใดก็ตามที่เรา ว่าไปตาม CLI specification ความสำเร็จที่ code ของเราจะทำงาน ได้ โดยไม่ยึดติด platform ก็มาถึง ปัจจุบัน นอกจาก นอกจาก Microsoft  ที่ดำเนินตาม CLI (Microsoft .NET) แล้ว  ก็มีอีกหลาย ๆ third party ที่พยายามจะ implement  CLI เจ้าหนึ่งที่กำลังมาแรง ผมคิดเองนะ ก็คือ Novell’s Open-source Mono Project นี่แหละครับคือประเด็นที่กล่าวมาทั้งหมด
ตอนนี้ Mono project ได้ทำการ implement CLI ให้กับหลาย plate form คือ Apple’s OS X  Linux และ ก็ Sun Solaris และอื่น ๆ อีก รวมถึง Microsoft Window ด้วย ทำแข่ง Micro Soft ซะ งั้นไม่รู้ว่าคิดอะไรอยู่ เอาว่าผมจะพูดถึงเรื่อง Mono project ในตอนต่อไป ก็แล้วกันนะครับ  ค่อยติดตามก็แล้วกัน

Delegates and Events ตอนที่ 3

October 12, 2008 2 comments

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

ครับจากที่ได้กล่าวมา ข้างต้น  delegates นั้นที่จริงแล้วเป็น multicast ก็หมายถึงโดยปกติแล้วมันสามารถที่จะชี้ไปยัง function หรือ method ได้หลาย method หรือ function ในคราวเดียวกัน  Base case ของ multicast delegates ก็คือ System.MulticastDelegate ครับ   ดังนั้น การเรียก delegates object ครั้งเดียวก็สามารถที่จะสั่งให้ หลาย method ทำงานได้ แต่ต้องไม่ลืมนะครับว่า Method เหล่านั้นต้องเป็นไปตามข้อกำหนดของ delegates นะครับ นี้สำคัญ นะครับ 🙂

Delegates and Events ตอนที่ 2

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

เอาละครับเรามาเข้าเรื่องของเราเลยดีกว่า เราจะดูตัวอย่างของ delegates อีก 2 ตัวอย่าง โดยจะพิจารณาการทำงาน ทีละขั้น นะครับ พิจารณา code ต่อไปนี้ เป็นตัวอย่างต่อไป

namespace ConsoleApplication1
{
    public class MyClass
    {
        public delegate void LogHandler(string message);

        public void Process(LogHandler logHandler)
        {
            if (logHandler != null)
            {
                logHandler(“Process() begin”);
            }
            if (logHandler != null)
            {
                logHandler(“Process() end”);
            }
        }
    }
    public class TestApplication
    {
        // Static Function: To which is used in the Delegate. To call the process() function
        static void Logger(string s)
        {
            Console.WriteLine(s);
        }
        static void Main(string[] args)
        {
            // Create an instance of the delegate , pointingto the logging function
            // this delegate will then be passed to the Process() function.
            MyClass myclass = new MyClass();
            MyClass.LogHandler myLogger = new MyClass.LogHandler(Logger);

            myclass.Process(myLogger);
        }
    }
}

จาก Code ข้างต้น หากเรา ทำการ Run ดู ก็จะได้ ผลการทำงาน เป็นอย่างนี้นะครับ

Process() begin
Process() end
ประมาณ นี้ เรามาลองพิจารณา Code กันดูนะครับ ว่า code ข้างต้นทำงานอย่างไร อย่าลืมว่าเรากำลัง ดูตัวอย่างการใช้งาน delegates      ในตัวอย่างนี้ เราจะประกาศ หรือ declare delegates ไว้ใน class ชื่อ MyClass  โดยให้ delegates มีชื่อว่า LogHandler โดยให้มี parameter 1 ตัว เป็น string ใช่ใหมครับ (บรรทัดที่ 5) เมื่อเราประกาศไว้เช่นนี้ นั่นก็หมายถึงว่า Function ที่เราต้องการ ทำ delegate ก็ต้องมี การประกาศในรูปแบบเดียวกัน นะครับ และจากตัวอย่างนี้ แสดงให้เห็น ว่า ตัว function อยู่ที่ไหน ก็ได้ใน namespace เดียวกัน ในตัวอย่างเราวางไว้ใน class TestApplication ซึ่งเป็น class ที่เราใช้เริ่มต้นการทำงาน

ในบรรทัด ที่ 22 – 25 เป็นส่วนที่เรา Implement  function ที่เราต้องการให้เป็น delegates ซึ่งไม่ได้ทำอะไรมากเพียงแต่ นำ parameters ที่ส่งเขามา แสดงผลที่หน้าจอด้วย WriteLine() นะครับ สังเกตุว่า  function นี้ เป็น อะไรครับ ใช้แล้วเป็น static function ด้วย  หลายคนคงพอเข้าใจนะครับ ว่าทำไมต้องทำให้เป็นอย่างนั้น ถามว่า ไม่เป็น static ได้ไหม ตอบว่าได้ แต่ต้องเรียกใช้ผ่าน object ของ TestApplication ใช่ไหมครับ  เพราะมัน เป็น static จึงเรียกใช้มันได้เลย นั่นแหละเป็น เหตุผล ครับ แต่ว่าตรงนี้คงไม่ใช้ประเด็น นะครับ มาดูกัน ครับ

บรรทัดที่ 7 – 18 คือ Function process มี Parameter 1  ตัว เป็นชนิด LogHandler  ซึ่งมันคือ delegates type ที่เราประกาศไว้ เวลาเราใช้งาน delegate เรามองมันคล้าย class หรือ object ก็ได้นะครับ จะไ้ด้สะดวกใจ     นั่นก็คือ function Process(LogHandler logHandler) นั้นรับ parameter เป็น delegate type นั่นเอง  หลังจากนั้น ใน body เป็นการใช้งาน delegates ที่ส่งผ่านเข้าไป ซึ่งการเรียกใช้ ก็เป็นลักษณะนี้

   logHandler("Process() begin");

ก็เป็นการส่ง string ให้กับ function นั่นแหละครับ  มาดูต่อใน Function Main กันนะครับ ที่ function Main นี้เราจะเริ่มใช้งาน ด้วยการ instantiate MyClass หรือ สร้าง object ที่ชื่อ myClass ขึ่นมา  และต่อมาเรา ก็ สร้าง instance ของ delegate โดยเรา ส่งชื่อ function เป็น argument

MyClass.LogHandler myLogger = new MyClass.LogHandler(Logger);

นั่นแหละครับเราก็จะได้ myLogger เป็น object ที่ชี้ไปที่  Logger ครับ เท่านี้เราก็พร้อมที่ส่ง มันไปทำงานที่ไหนก็ได้ตามต้องการ สำหรับตัวอย่างของเรา ส่งกลับไปเป็น Argument ของ  myclass.Process() ดังนี้

myclass.Process(myLogger);

หลังจากนี้ผมคงไม่ต้อง อธิบายต่อนะครับว่ามันเป็นอย่างไรต่อไป

ครับ จากตัวอย่างคงพอจะเห็นการทำงานเพิ่มขึ้นนะครับ ว่า delegate ทำงานอย่างไร  คิดว่าหลายคนยังคงมีคำถามหลาย ๆ คำถามอยู่ในใจ ผมคิดว่าหลาย ๆ คำถามอีกเช่นกัน ท่านสามารถทดลอง หาคำตอบได้ด้วยตนเอง ฮิ ฮิ คือว่าขี้เกียจตั้งคำถามอะครับ

อีกสักตัวอย่างเป็นไงครับ ดูตัวอย่างนี้ดีกว่านะครับ Advance ขึ้นมาอีก

using System.IO;

namespace ConsoleApplication1
{
public class MyClass
{
public delegate void LogHandler(string message);

public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler(“Process() begin”);
}
if (logHandler != null)
{
logHandler(“Process() end”);
}
}
}
// The FileLogger class merely encapsulates the file I/O
public class FileLogger
{
FileStream fileStream;
StreamWriter streamWriter;

// Constructor
public FileLogger(string filename)
{
fileStream = new FileStream(filename, FileMode.Create);
streamWriter = new StreamWriter(fileStream);
}

// Member Function which is used in the Delegate
public void Logger(string s)
{
streamWriter.WriteLine(s);
}

public void Close()
{
streamWriter.Close();
fileStream.Close();
}
}
public class TestApplication
{
static void Main(string[] args)
{
FileLogger fl = new FileLogger(“process.log”);

MyClass myClass = new MyClass();

// Crate an instance of the delegate, pointing to the Logger()
// function on the fl instance of a FileLogger.
MyClass.LogHandler myLogger = new MyClass.LogHandler(fl.Logger);
myClass.Process(myLogger);
fl.Close();
}
}
}

เอาละครับ หลังจาก ดู code กันแล้วหลายคน คงพอเข้าใจ หลายคนคงถูกใจเพราะตรงกับคำถามในใจจาก ตัวอย่างที่แล้ว ครับในตัวอย่างนี้ เราสร้าง class ใหม่ขึ้นมานะครับ ชื่อว่า FileLogger แล้ว ใน class นี้เราก็มี method สำคัญของเรา คือ Logger เราย้ายมาไว้ใน class นี้เพื่อให้เห็นการทำงานที่แตกต่างออกไปอีก นั้นก็หมายถึงว่า ไม่ว่า function ที่ต้องการใช้เป็น delegate จะอยู่ที่ไหนก็ตาม เราก็สามารถใช้งานมันได้ ครับ ขอเพียงว่าให้เป็นไปตามข้อกำหนดของ การทำ delegates ก็แล้วกัน เอาล่ะครับ ตัวอย่างนี้คงไม่ต้อง พูดกันมากนะครับ เนื่องจากการประกาศ delegates นั้นใช้ของเดิมจากตัวอย่างที่แล้ว แต่ delegate  funciton นั้น อยู่ใน class อีก class หนึ่งและก็ไม่ได้เป็น static method ด้วย ดังนั้นการที่จะเข้าถึง fuction Logger ก็ต้อง ทำผ่าน instance ของ class FileLogger นะครับ ดังนั้นใน Main method จึงได้ instantiate f1 ให้เป็น Object ของ FileLogger ขึ้นมา ซึ่งจะต้องสึ่งชื่อไฟล์ให้กับ Constructor ของ FileLogger ด้วยนะครับ ชื่อ ว่า process.log ตามนี้

FileLogger fl = new FileLogger(“process.log”);

เพื่อให้เราสามารถอ้างอิง เจ้า Logger ได้นั่นเอง หลังจากนั้น เราก็ส่ง  f1.Logger ให้กับ delegates  object ใช่ใหม ครับ แล้วเจ้า instance ของ delegates ก็อ้างอิงมายัง f1.Logger มันก็เหมือนเราเรียกใช้ f1.logger โดยการอ้างอิงผ่านทาง address นั่นเองครับ

MyClass.LogHandler myLogger = new MyClass.LogHandler(fl.Logger);

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

จบก่อนนะครับ สำหรับ ตอนต่อไป จะเป็นเรื่อง Multicasting เน่อ   🙂

Categories: C# .NET, DOT NET

Delegates and Events ตอนที่ 1

Class ต่าง ๆ เป็น Reference type  หมายถึง ตัวแปรของ Obeject ของ Class นั้น ไม่ได้อ้างอิงไปยัง Object โดยตรง แต่ชี้ไปยังที่ตำแหน่งใน Address ของ Object แทน ซึ่งทำให้เราสามารถใช้งาน Object ในรูปแบบพิเศษได้มากมาย  Delegates ก็เป็นตัวแปรอีกชนิดหนึ่งที่เป็นลักษณะ Reference type  Deletgates นั้น สามารถที่จะชี้ไปยัง Method หรือ Reference ไปยัง Method ได้ในขณะ runtime  นั่นก็หมายถึงเราสามารถ ที่จะเลือกได้ว่า เราจะ สั่ง Method ไหนทำงานก็ได้ ในขณะ runtime  ขึ้นอยู่กับ ความต้องการในขณะนั้น

ในส่วนนี้ผมจะพูดถึงเรื่อง การสร้าง Deletgates  การทำ multicast delegates และ วิธีการใช้ event กับ delegates

Deletgates เป็นตัวแปร แบบ Reference type สามารถที่จะอ้างอิงไปยัง method ใด ๆ ก็ได้  delegate ใน C# คล้ายกับ function pointer ใน C++   เพื่อให้เกิดความเข้าใจ พิจารณาจาก code ต่อไปนี้

// Delegate declaration
public delegate void MyDelegate(string ArgValue);

public void DelegateFunction(string PassValue)
{
// Method implement here
}
public void UseMethod()
{
// Delegate Instantiation
MyDelegate DelegateObject = new MyDelegate(DelegateFunction);

}

จาก code ด้านบน บรรทัดแรกคือการประกาศ delegate สังเกตุรูปแบบของการประกาศเป็นไปตาม syntax นี้
delegate <return type> <delegate-name> <parameter list>
จาก code ตัวอย่าง delegate ชื่อ MyDelegate ไม่ return ค่าและมี parameter 1 ตัวคือ PassValue ซึ่งมีชนิดเป็น string สำหรับ function ที่เราจะทำ delegate ก็จะต้อง มีการกำหนด signature ให้ตรงกับ delegate ที่ประกาศไว้ จากตัวอย่าง คือ function ถัดมา ชื่อว่า DelegateFunction ซึ่งได้มีการประกาศ signature ไว้ตรงกับ delegate ด้านบนทุกประการ หลังจากนั้น การใช้งานเราจำทำการ instantiate Delegate object คล้ายกับการ Instantiat object ของ Class  เพียงแต่ว่า นี้เป็น object ที่เป็นdelegate โดยจะส่งชื่อ function ที่ต้องการเป็น Parameter ของ delegate constructure

Mydelegate DelegatObject = new MyDelegate(DelegateFunction);

หลังจากนั้น การใช้งานเราสามารถที่จะเรียก DelegateObject แทนชื่อ function ได้เลยและเป็นลักษณะ reference สามารถที่จะส่งผ่าน DelegateObject เป็น argument ของfunctionใด ๆ ที่ต้องการใช้ function เป็น parameter ไ้ด้เลย ซึ่งจะไ้้้่ด้เห็นการใช้งานในรูปแบบต่าง ๆต่อไป

การใช้งาน Delegate

เพื่อให้เห็น ภาพมากขึ้นจะขอยกตัวอย่างการเรียกใช้ function ปกติขึ้นมาพิจารณาเพื่อนำไปสู่การใช้งาน ขอให้พิจารณาจากตัวอย่างนี้นะครับ


namespace MyNameSpace.NoDelegate
{
    public class MyClass
    {
        public void Process()
        {
            Console.WriteLine("Process() begin");
            Console.WriteLine("Process() end");
        }
    }
    public class Test
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            myClass.Process();
        }
    }
}

จาก ตัวอย่าง เป็นการใช้งานทั่วไปสำหรับการเรียกใช้ function สมมุติว่าถ้าหากเราไม่ต้องการเรียกใช้ function ตรง ๆ หล่ะหากเราต้องการที่จะส่งผ่าน function นี้ให้กับ function อื่นเรียกใช้อีกที โดยเฉพาะการทำงานในลักษณะ event-driven เรามาดูการ ใช้ delegate จากตัวอย่างเดียวกัน

Very basic delegate


namespace ConsoleApplication1
{
    public class MyClass
    {
        public delegate void WriteHandler(string message);
        public void Process(WriteHandler writeh)
        {
            writeh("Process() begin");
            writeh("Process() end");
        }
        public void writer(string message)
        {
            Console.WriteLine(message);
        }
    }
    public class Program
    {
        static void Main(string[] args)
        {
            MyClass myclass = new MyClass();
            MyClass.WriteHandler writehander = new MyClass.WriteHandler(myclass.writer);
            myclass.Process(writehander);
        }
    }
}

ผลของการ ทำงาน จะได้เช่นเดียวกับโปรแกรมแรกนะครับ แต่โปรแกรมนี้เราใช้คุณลักษณะของ delegate พิจารณา class Myclass จะเห็นว่ามีการ ประกาศ Delegate  ชื่อ ว่า WriteHandler มี parameter 1 ตัวคือ message และไม่มีการ return ค่าดังนั้น function ที่เราต้องการทำ delegation คือ writer สังเกตุว่า มี signature เหมือนกัน

หลังจากนั้น เราต้องการส่งผ่านฟังก์ชันนี้เขาไปทำงานใน method ชื่อ Process นะครับ สังเกตุว่า Parameter ของ Process นั้นเป็นชนิดเดียวกับ delegate

แล้วสุดท้ายเ้รามาดูที่ class program  ที่ Main เราจะเห็นว่า จะมีการ instantiate delegate object ชื่อ writehander แล้วส่ง method ชื่อ writer เป็น argument ผลก็คือได้ writerhandler ที่อ้างอิงไปยัง writer เราก็โยน writerhandler เข้าไปให้ Process เป็นการส่งผ่าน parameter แบบ reference นะครับ  จะเห็นว่าการทำงานครั้งนี้ เราส่งผ่าน function หรือ method เป็น parameter นะครับ นี่แหละการทำงานของ delegate ครับ จะเห็นว่าการทำงานของ delegate นั้นมีขั้นตอนดังนี้นะครับ

  • Delclaration
  • Instantiation
  • Invocation

จากตัวอย่างที่แล้ว หลายท่านที่เป็น มือใหม่อาจจะยังมึน ๆ ขอตบท้ายด้วย ตัวอย่าง ง่าย ๆ อีกหนึ่งตัวอย่างนะครับ

using System;

namespace Mynamespace.BasicDelegate
{
    // #1 Declaration
    public delegate void SimpleDelegate();

    class TestDelegate
    {
        public static void MyFunc()
        {
            Console.WriteLine("I was called by delegate ...");
        }
        public static void Main()
        {
            // #2 Instantiation
            SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);
            // #3 Invocation
            simpleDelegate();
        }
    }
}

เป็นงั้ยครับ พอจะได้ concept ใหม่ครับ ลอง run code ดูนะครับแล้วจะเข้าใจ สำหรับ delegate ขอพอแค่นี้ก่อนนะครับ ขอให้ติดตาม ในตอน ต่อ ๆไปนะครับเนื่องจากมีการใช้งานอีก หลายลักษณะ  ขอให้มีความสุขกับการเรียนรู้นะครับ

Categories: C# .NET Tags: