ตอน 29 Regex และ Generic

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

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

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

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

 

Regex (Regular Expression)

 

Regex คือเครื่องมือที่ช่วยในการจัดการกับข้อความ (string) ได้ง่ายและรวดเร็ว การจัดการนี้รวมถึง การค้นหา เปรียบเทียบรูปแบบ แก้ไขเปลี่ยนแปลง กระจายคำ (parse) ตัดทอน ลบ แทนที่ นำมาเชื่อมกัน ซึ่งมีประโยชน์ในการจัดการข้อมูลที่เป็น string เช่นข้อความและไฟล์ HTML เป็นต้น

คลาสต่างๆ ที่จัดการเรื่อง Regex จะอยู่ใน name space System.Text.RegularExpressions;

โค้ดตัวอย่างต่อไปนี้ใช้ method Match.Result เพื่อตัดเฉพาะ protocol และหมายเลข port ออกมาจาก URL ยกตัวอย่างเช่น หากป้อน URL ต่อไปนี้ให้ http://www.contoso.com:8080/letters/readme.html

ผลลัพธ์ที่ได้จะเป็น

http:8080

โค้ดเป็นดังนี้

String Extension(String url)
{
   Regex r = new Regex(@"^(?<proto>\w+)://[^/]+?(?<port>:\d+)?/",       
                        RegexOptions.Compiled);
   return r.Match(url).Result("${proto}${port}");
}

โค้ดตัวอย่างต่อไปนี้ตรวจสอบความถูกต้องของ email address

String Extension(String emailAddress)
{
   Regex r = new Regex("(?<user>[^@]+)@(?<host>.+)");
   return r.Match(emailAddress);
}

รายละเอียดเรื่อง Regex ยังมีพิสดารกว่านี้มาก สามารถนำไปเขียนเป็นตำราได้ต่างหากอีกหนึ่งเล่ม สำหรับขอบเขตของหนังสือเล่มนี้ เท่าที่ผู้เขียนอธิบายมาถือว่าเพียงพอแก่การแล้ว

ข้อสรุปเรื่อง Regex

  • เป็นเหมือนอีกภาษาหนึ่งที่ซ้อนอยู่ภายในภาษา C#
  • มีประโยชน์ในการประมวลผลเกี่ยวกับกลุ่มคำและสายอักขระ
  • คลาสต่างๆ ที่จัดการเรื่อง Regex จะอยู่ใน name space System.Text.RegularExpressions;

 

Generic

Generic เป็นคุณสมบัติใหม่ที่เพิ่มมาในภาษา C#2.0 (และ CLR ด้วย) เป็นกลไกที่ทำให้เราสามารถนิยามคลาสหรือ method ที่อาจกลายเป็น type อะไรก็ได้ในภายหลัง generic เป็นคุณสมบัติที่ทรงพลังที่สุดในบรรดาคุณสมบัติต่างๆ ที่เพิ่มเข้ามาใน C#2.0 เพราะช่วยแก้ปัญหาเรื่องการที่ต้องเขียนโค้ดให้ทำงานกับ type ใด type หนึ่งเป็นการเฉพาะเจาะจง ผู้เขียนขอยกตัวอย่างประโยชน์การใช้งานของ generic ดังต่อไปนี้

ใน C# เวอร์ชันแรกๆ หากเราเขียนคลาสหรือ method เพื่อจัดการกับข้อมูล เราจะใช้ได้กับ type ใด type หนึ่งเท่านั้น ยกตัวอย่างเช่นเขียนคลาสเพื่อจัดการกับ stack ซึ่งจะมี method push() และ pop() ค่าที่เราต้องให้ push() หรือ pop() ต้องเป็น type ใด type หนึ่ง เช่น int หรือ string ดังนั้นหากต้องการ stack ที่จัดการข้อมูลได้หลายๆ แบบเราก็ต้องสร้างคลาส stack หลายๆ แบบซึ่งไม่ใช่วิธีที่ดีในการเขียนโปรแกรม ดังตัวอย่างโค้ดต่อไปนี้

public class IntStack
{
   public void Push(int item) { }
   public int Pop() { }
}
static void Main()
{
   IntStack stack = new IntStack();
   stack.Push(1);
   int number = stack.Pop();
}

โค้ดข้างบนคือตัวอย่างคลาส stack ที่จัดการกับข้อมูลแบบ int และคลาสที่เรียกใช้ stack ดูตัวอย่างต่อไป

public class StringStack
{
   public void Push(string item) { }
   public string Pop() { }
}
static void Main()
{
   StringStack stack = new StringStack();
   stack.Push("1");
   string number = stack.Pop();
} 

โค้ดข้างบนคือตัวอย่างคลาส stack ที่จัดการกับข้อมูลแบบ string และคลาสที่เรียกใช้ stack

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

public class Stack
{
   public void Push(object item) {}
   public object Pop(){}
}
static void Main()
{
   Stack stack = new Stack();
   stack.Push("1");
   stack.Push(1);
   string number = stack.Pop().ToString();
   int number2 = (int)stack.Pop();
}

โค้ดข้างบนคือตัวอย่างคลาส stack ที่จัดการกับข้อมูลแบบ object และคลาสที่เรียกใช้ stack โปรดสังเกตว่าการใช้งานต้องทำ boxing และ unboxing ตลอด

generic ถูกสร้างมาเพื่อแก้ปัญหานี้ มันทำให้เราสามารถนิยามคลาสหรือ method ที่ใช้กับ type อะไรก็ได้โดยไม่ทำให้โปรแกรมด้อยประสิทธิภาพและสูญเสียความเป็น type safety โปรดพิจารณาโค้ดตัวอย่างต่อไปนี้

1    public class Stack<T>
2    {
3       public void Push(T item) { }
4       public T Pop() { }
5    }
6    static void Main()
7    {
8       Stack<int> stack = new Stack<int>();
9       stack.Push(1);
10      stack.Push(2);
11      int number = stack.Pop();
12   } 

โค้ดข้างบนคือตัวอย่างคลาส stack ที่จัดการกับข้อมูลแบบ generic และคลาสที่เรียกใช้ stack โปรดสังเกตว่าชื่อคลาสจะตามด้วย <T> (บรรทัดที่ 1) ซึ่งเป็นการประกาศว่าคลาสนี้เป็นแบบ generic โปรดสังเกตต่อไปอีกว่า argument ของ method Push()(บรรทัดที่ 3) และ return type ของ method Pop()(บรรทัดที่ 4) มี type เป็น T ซึ่งหมายถึง generic ด้วยเช่นกัน

โปรแกรมที่เรียกใช้คลาส stack (คือ Main) จะเป็นผู้กำหนดว่าคลาส stack จะมี type เป็นแบบใด ในโค้ดตัวอย่างกำหนดให้เป็น int (บรรทัดที่ 8) จากนั้นจะสามารถ push ข้อมูลเป็น int ได้ (บรรทัดที่ 9 และ 10) และ pop ข้อมูลมาเป็น int (บรรทัดที่ 11) ได้เช่นเดียวกัน

นอกจากใช้ generic กับคลาสแล้ว เรายังสามารถใช้ generic กับสมาชิกของคลาสได้ด้วย เช่น

ใช้ generic กับสมาชิกของคลาสที่เป็น field

class test<T>
{
    private T foo;
} 

ใช้ generic กับสมาชิกของคลาสที่เป็น property

public T Foo
{
   get { return foo; }
   set { foo = value; }
} 

ใช้ generic กับสมาชิกของคลาสที่เป็น method (ใช้ได้ทั้ง return type และพารามิเตอร์)

public T Foo(T bar)
{
   return bar;
} 

ข้อสรุปเรื่อง generic

  • generic เริ่มมีใช้ใน C#2.0
  • generic อยู่ใน name space System.Collections.Generic ของ .NET Framework class library เวอร์ชัน 2.0 ขึ้นไป
  • generic ช่วยแก้ปัญหาการที่โค้ดต้องทำงานกับ type ใด type หนึ่งได้เท่านั้น
  • generic ปลดเปลื้องภาระของ heap จาก boxing และ unboxing
  • จะใช้ generic กับคลาสหรือสมาชิกของคลาสก็ได้

ตอนต่อไป: Operator overloading

Post a comment or leave a trackback: Trackback URL.

ความเห็น

  • Death  On ธันวาคม 13, 2007 at 3:44 pm

    งง ๆ กะเรื่อง Generic นิดหน่อยค่ะ
    แต่ก้อดีมาก ๆ เลยค่ะ ที่เอามาลงให้อ่าน
     
    ขอบคุณมาก ๆ ค่ะ จะเข้ามาติดตามเรื่อย ๆ

ใส่ความเห็น

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / เปลี่ยนแปลง )

Twitter picture

You are commenting using your Twitter account. Log Out / เปลี่ยนแปลง )

Facebook photo

You are commenting using your Facebook account. Log Out / เปลี่ยนแปลง )

Google+ photo

You are commenting using your Google+ account. Log Out / เปลี่ยนแปลง )

Connecting to %s

%d bloggers like this: