protect
ถ้าเอาบทความไปเผยแพร่แล้วไม่ให้เครดิต ดำเนินคดีด้วย พรบ. คอมพิวเตอร์ฉบับใหม่ ขั้นสูงสุดและไม่ยอมความครับ
วันจันทร์ที่ 28 กันยายน พ.ศ. 2558
type conversion แบบ explicit และ implicit ตอนที่ 3
ในตอนที่ 2 ผมแสดงให้เห็นการ convert Type ถ้าเลือก Type ไม่เหมาะสม ตัวแปรที่เก็บค่าอาจจะมีความผิดพลาดได้ และผมได้ทิ้งคำถามว่าถ้างั้นเราใช้ Type ที่เก็บค่าได้มากๆ เลยดีไหมจะทำให้ไม่มีการผิดพลาดในการเก็บข้อมูล
เพื่อพิสูจน์ความคิดนี้เรามาลองดูตัวอย่าง code นี้น่ะครับ
const int _count = 1000000;
long bytes1 = GC.GetTotalMemory(true);
int[] array = new int[_count];
array[1] = int.MaxValue;
long bytes2 = GC.GetTotalMemory(true);
long difference = bytes2 - bytes1;
double per = (double)difference / _count;
Console.WriteLine("Program used: {0:0.0} MB",
(double)difference / (1024 * 1024));
Console.WriteLine("Each decimal element required: {0:0.0}
bytes", per);
ในตัวอย่าง โปรแกรมมีการถาม GC (Garbage Collector - ผมจะอธิบายอย่างละเอียดในบทความถัดๆ ไปครับ) ว่า ณ ตอนนี้โปรแกรมมีการใช้หน่วยความจำไปเท่าไร ด้วยคำสั่ง
long bytes1 = GC.GetTotalMemory(true);
จากนั้นโปรแกรมจะทำการจองหน่วยความจำ โดยทำการสร้าง Array ที่เก็บข้อมูลชนิด integer จำนวน 1,000,000 dataและให้ array ตำแหน่งที่ 1 เก็บค่ามากที่สุดของ Type ชนิด integer.
int[] array = new int[_count];
array[1] = int.MaxValue;
จากนั้นโปรแกรม ถาม GC อีกครั้งว่าโปรแกรมมีการใช้หน่วยความจำไปเท่าไร
long bytes2 = GC.GetTotalMemory(true);
ดังนั้นโปแกรมก็จะรู้ว่าการจองหน่วยความจำ array เพื่อเก็บข้อมูลชนิด integer จำนวน 1,000,000 ใช้หน่วยความจำไปเท่าไรด้วยคำสั่ง
long difference = bytes2 - bytes1;
และจาก code โปรแกรมยังบอกหน่วยความจำที่ใช้แต่ล่ะ array ด้วยคำสั่ง
double per = (double)difference / _count;
จากนั้นโปรแกรมก็พิพม์ผลออกทางหน้าจอ
Console.WriteLine("Program used: {0:0.0} MB",
(double)difference / (1024 * 1024));
Console.WriteLine("Each decimal element required: {0:0.0}
bytes", per);
สำหรับ Console.WriteLine("Program used: {0:0.0} MB",(double)difference / (1024 * 1024)); สามารถเขียนได้อีกแบบ คือ
Console.WriteLine("Program used: " + ((double)difference / (1024 * 1024)).ToString("0.0") + " MB");
เนื่องจาก GC.Collector จะ ให้ค่ามีหน่วยเป็น byte
ถ้าหารด้วย 1024 เราก็จะได้หน่วยที่เป็น KB
ถ้าหารด้วย 1024*1024 เราก็จะได้หน่วยที่เป็น MB
ที่นี้เรามาดูผลการรันน่ะครับ
จะเห็นว่าโปรแกรมใช้หน่วยความจำไป 3.8M เราแต่ล่ะ block ของ array จะใช้หน่วยความจำ 4 byte
ที่นี้เราลองมาเปลี่ยน code เป็นดังนี้
const int _count = 1000000;
long bytes1 = GC.GetTotalMemory(true);
decimal[] array = new decimal[_count];
array[1] = int.MaxValue;
long bytes2 = GC.GetTotalMemory(true);
long difference = bytes2 - bytes1;
double per = (double)difference / _count;
Console.WriteLine("Program used: {0:0.0} MB",
(double)difference / (1024 * 1024));
Console.WriteLine("Each decimal element required: {0:0.0}
ytes",per);
ในตัวอย่าง code ที่สองเปลี่ยนแค่ array ที่เก็บ Type ชนิด integer ไปเก็บ Type ที่เป็น decimal
ลองดูผลการรันโปรแกรม
จะเห็นว่ามีการใช้หน่วยความจำไปถึง 15.3 MB ทั้งๆ ที่เก็บข้อมูลเหมือนๆ กับตัวอย่าง code แรก
จากผลการทดลองนี้เราก็สรุปได้ว่า การใช้ตัวแปรที่เก็บข้อมูลได้เยอะโปรแกรมก็จะต้องการหน่วยความจำมากขึ้นดังนั้นเมื่อเราเขียนโปรแกรมเราจึงควรเลือกใช้ Type ให้เหมาะสม โดยเฉพาะตัวแปรของ library ที่พัฒนาเพื่อให้คนอื่นนำไปใช้
พบกันใหม่ในบทความหน้าครับ
TuChay
type conversion แบบ explicit และ implicit ตอนที่ 2
จากตอนที่ 1 เราเห็นแล้วว่า การใช้ explicit กับ implicit จะมีรูปแบบการเขียน code เหมือนกัน ในตอนนี้เราจะมาดูข้อแตกต่างกันน่ะครับ
op_implicit
จะใช้สำหรับการแปลง Type โดยที่ไม่สนใจกับการสูญหายของข้อมูลและความแม่นยำในการแปลง ตัวอย่างเช่น Type ชนิด Decimal เมื่อแปลงเป็น Type ชนิด integer ข้อมูลบางส่วนอาจจะหายได้
ลองดู code ตัวอย่างน่ะครับ
double testDouble = (double)Int32.MaxValue + 1;
int testInt = (int)testDouble;
Console.WriteLine("double value = " + testDouble.ToString());
Console.WriteLine("int value = " + testInt.ToString());
เมื่อเราทำการ run software จะได้ดังรูป
จะเห็นว่าถ้าค่าที่แปลงน้อยกว่า 2,147,483,648 การแปลงจาก Type ชนิด double ไปเป็น Integer จะไม่มีปัญหาแต่ถ้าเกินเมื่อไรค่าที่ได้จะให้ตัวเลขที่ผิดพลาดทันที
op_explicit
จะใช้สำหรับการแปลง Type โดยที่สนใจกับการสูญหายของข้อมูลหรือต้องการความแม่นยำในการแปลงเช่น การแปลง Type ชนิด Decimal ไปเป็น Double
ลองดูตัวอย่าง code น่ะครับ
decimal testDecimal = Decimal.MaxValue;
double testDouble = (double)testDecimal + 1;
Console.WriteLine("decimal value = " + testDecimal.ToString());
Console.WriteLine("double value = " + testDouble.ToString());
เมื่อเราทำการ run software จะได้ดังรูป
จะเห็นว่าเมื่อแปลงข้อมูลมาแล้ว ข้อมูลยังคงถูกต้องเสมอ
จากตัวอย่างจะเห็นว่างั้นเราควรเลิกใช้ int แล้วหันมาใช้ decimal อย่างเดียวกันดีกว่าเพราะการแปลงข้อมูลแม่นยำมาก .... ในบทความหน้าผมจะแสดงให้ดูครับว่าเราควรเลิกใช้ int โดยเปลี่ยนไปใช้ decimal ดีกว่าหรือเปล่า
พบกันใหม่บทความหน้าครับ
TuChay
วันพฤหัสบดีที่ 24 กันยายน พ.ศ. 2558
Type conversion แบบ explicit และ implicit ตอนที่ 1
ผมได้อธิบายเกี่ยวกับ Type และ CLS มาได้หลายบทความแล้ว วันนี้ผมจะอธิบายเกี่ยวกับ การ convert Type ซึ่งเป็นคนล่ะอย่างกับการ convert ตัวแปร ผมเข้าใจว่าผู้อ่านคงรู้จักการ convert ชนิดตัวแปร เช่นการ convert จาก ตัวเลขเป็นตัวหนังสือโดยใช้ method ToString() หรือการ cast ตัวแปรเช่น (int)100
ในชุด .Net Framework มี operation ในการ convert Type อยู่ 2 อย่างคือ op_Implicit กับ op_Explicit วิธีการใช้การ convert Type ของทั้งอย่างจะเหมือนกัน แต่ข้อแตกต่างผมจะไปอธิบายในตอนที่ 2 น่ะครับ ตอนนี้ผมจะอธิบายวิธีใช้ของทั้งคู่ได้ยังไงบ้าง
สมมุติผมมี Type ที่ชื่อ Currency ซึ่งมีรายละเอียดดังนี้
public class Currency
{
public double Rate;
public string Sign;
public Currency(double rate, string sign)
{
Rate = rate;
Sign = sign;
}
public static implicit operator double(Currency rhs)
{
return rhs.Rate;
}
}
จาก code ข้างบนเรามา focus ที่ method นี้ น่ะครับ
public static implicit operator double(Currency rhs)
ในที่นี้เราจะบอก compiler ว่าเรามี method ชนิด static ที่เป็น operator double โดยมีการรับค่าเข้ามาเป็น Type Currency และมีการ return ค่าที่เป็น Type double
ตรงนี้สำคัญน่ะครับ Type ที่จะ return ออกไปจะต้องเป็น Type ชนิดเดียวกับ operator ในตัวอย่างนี้ method คือ operator double ดังนั้น Type ที่จะ return จะต้องเป็น Type double ตรงนี้สำคัญมาก
เมื่อมาดูที่ IL code เราจะเห็นว่า C# compiler ได้สร้าง method ที่ชื่อ op_Implicit : float64(class ImplicitTester.Currency)จริงๆ วิธีการตั้งชื่อก็มาจากการนำคำว่า "op_Implicit" มาเป็นชื่อ method เลย โดยที่จะมีการ convert Type ชนิด Currency ไปเป็น float64
เมื่อเรา double click ที่ method op_Implicit : float64(class ImplicitTester.Currency) เราจะได้ IL code ของ method นี้ดังรูปข้างล่าง
ที่นี้เรามาดูตัวอย่างวิธีการใช้ implicit operator ของ Type Currency กับครับ
Currency thai = new Currency(35.20, "BTH");
Console.WriteLine((double)thai);
ที่คำสั่ง (double)thai ก็คือ method public static implicit operator double(Currency rhs) นั้นเอง โดย (double) ก็คือ operator double และ Thai ก็คือ Type ชนิด Currency ตัวอย่างนี้ถ้าพูดเป็นภาษาไทยง่ายๆ ก็คือการแปลง Type ชนิด Currency ไปเป็น Type double
ที่นี้เรามาลองเพิ่ม explicit operator ของ Type Currency ดูน่ะครับ (ตัวอย่างข้างบนเป็น implicit operator น่ะครับ อย่าเพิ่งงง)
public static explicit operator string(Currency rhs)
{
return rhs.Sign;
}
จะเห็นว่า operator ของ method นี้เป็น Type ชนิด string นั้นหมายความ method นี้จะต้อง return ค่าออกมาเป็น string
เมื่อ C# compiler ทำการ compile code ตัว compiler ก็จะสร้าง method ขึ้นมาใหม่ชื่อ op_Explicit ตามรูปข้างล่าง
method op_Explicit จะทำการ convert Type Currency ออกมาเป็น string
และเมื่อ doublic clik เพื่อเข้าไปดู code ข้างใน method ก็จะได้ดังรูปข้างล่าง
สำหรับตัวอย่างวิธีการใช้ก็คือ
Currency thai = new Currency(35.20, "BTH");
Console.WriteLine((string)thai);
ลองมาดูตัวอย่างสุดท้าย โดยการเพิ่ม operator Currency ลงไปใน Type Currency
public static explicit operator Currency(string sign)
{
return new Currency(0, sign);
}
วิธีการใช้ก็ตามตัวอย่างข้างล่างครับ
Currency cny = (Currency)("CNY");
พูดง่ายๆ ก็คือ convert Type ที่เป็น string ไปเป็น Type Currency
รูปแบบการเขียน code ระหว่าง explicit และ implicit จะเหมือนกันแต่วิธีการเอาไปใช้จะแตกต่างกันเล็กน้อยซึ่งผมจะอธิบายพร้อมยกตัวอย่างในตอนที่ 2 ครับ
พบกันใหม่บทความหน้าครับ
TuChay
วันอังคารที่ 22 กันยายน พ.ศ. 2558
CLS ตอนกฏเกี่ยวกับ การตั้งชื่อ
ที่นี้มาดูกฏข้อถัดไปของ CLS น่ะครับ ในบทความนี้จะเป็นเรื่องของการตั้งชื่อ ภาษาของตระกูล.Net Framework มีทั้งเป็นแบบ case sensitive และ case insensitive คือ ตัวหนังสือตัวใหญ่กับตัวเล็ก จะมีผลกับการ compile code เช่น ภาษา Visual Bais จะไม่มีผลแต่กับบางภาษาเช่น ภาษา C# ตัวใหญ่กับตัวเล็กจะมองเห็นเป็นคนล่ะตัวกัน
ตัวอย่าง code ข้างล่างเมื่อ compile มาแล้วจะได้ warning message เกี่ยวกับ CLS-compliant
using System;
[assembly:CLSCompliant(true)]
namespace CLS
{
public class person
{
}
public class Person : person
{
}
}
เนื่องจาก code มี 2 Type คือ person กับ Person ถ้าในแง่ของ C# Type ทั้ง 2 ตัวนี้ถือเป็นคนล่ะชนิดกัน แต่ถ้าเรา compile เป็น DLL แล้วไปใช้กับภาษา Visual Basic.Net ตัว Visual Basic จะแยกไม่ออกระหว่าง person กับ Person เพราะ Visual Basic จะมองเห็นเป็น Type ชนิดเดียวกัน
นอกจากนั้นการตั้งชื่อ Type หรือชื่อ class เราไม่สามารถนำ คำสงวน มาตั้งเป็นชื่อได้ ถ้าในภาษา C# compiler จะ compiler จะ return error ทันที ถ้ามีการนำคำสงวนมาใช้ แต่กับภาษา Visual Basic .Net ตัว compiler อนุญาติให้นำคำสงวนมาใช้ได้โดยใช้ "[" กับ "]" ครอบตัวชื่อ Type
ดูตัวอย่าง code ของ Visual Basic น่ะครับ
Public Class [case]
Private MyName As String
Public Sub New(ByVal name As String)
Me.MyName = name
End Sub
Public ReadOnly Property ClientName As String
Get
Return Me.MyName
End Get
End Property
End Class
จะเห็นว่าในตัวอย่าง code มีการนำคำสงวน case มาตั้งเป็นชื่อ Type ถ้าเราเจอแบบนี้ เราสามารถเรียกใช้ได้ใน ภาษา C# โดยใช้ @ นำหน้า Type นั้นๆ ดู ตัวอย่าง code ที่เรียกใช้โดย C# ข้างล่างเลยครับ
@case ca = new @case("TEST");
Console.WriteLine(ca.ClientName);
พบกันใหม่บทความหน้าครับ
TuChay
วันพฤหัสบดีที่ 17 กันยายน พ.ศ. 2558
CLS ตอนกฏเกี่ยวกับ Type
จริงๆ บทความนี้เป็นตอนที่ 3 ต่อจาก ตอนที่ 2 แต่ผมดูจากเนื้อหาแล้วน่าจะเยอะและแต่ล่ะตอนก็ไม่ได้ต่อเนื่องกันเลยเปลี่ยนชื่อบทความเป็นชื่อตอนน่ะครับ
ที่นี้เรารู้แล้วว่า CLS compliant เป็นกฏที่ Microsoft สร้างขึ้นเพื่อที่เป็นข้อกำหนดการใช้ library ร่วมกันระหว่างภาษาในตระกูล .Net Framework ในบทนี้เราจะพูดกันถึงเรื่อง กฏที่เกี่ยวกับ Type
ก่อนอื่นตกลงกันก่อนว่า Type ที่ Microsoft หมายถึงก็คือ ชื่อ class ของ C# นั้นเอง
ในกฏนี้จะบังคับใช้สำหรับ 4 กรณีน่ะครับ [อ่าน description แล้วอาจจะ งงๆ มันจะคล้ายๆ ภาษากฏหมาย ลองดูตัวอย่าง เพื่อเพิ่มความเข้าใจน่ะครับ]
1 กฏจะมีผลสำหรับ Type ที่เป็น public เท่านั้น
ตัวอย่าง code
using System;
using System.Runtime.InteropServices;
[assembly: CLSCompliant(true)]
namespace CLSLib
{
public class PersonController
{
}
class Person
{
}
}
จากตัวอย่าง code กฏที่เกี่ยวกับ Type จะมีผลเฉพาะ Type PersonController เท่านั้น Type Person จะไม่มีผลกับ CLS-compliant และสมาชิกของ Person ก็จะไม่มีผลกับกฏ CLS-Compliant เช่นกัน
2 กฏจะมีผลสำหรับสมาชิกของ Type ที่เป็น public ของ Type ชนิด public
ตัวอย่าง code
public class PersonController
{
private UInt16 _age;
public Int16 Age
{
get { return (Int16)_age; }
}
public PersonController()
{
}
}
จากตัวอย่าง code สมาชิก _age ของ PersonController จะไม่มีผลกับกฏ CLS-Compliant แต่สมาชิก Age เป็นชนิด public จึงต้องทำให้ถูกกฏ CLS-Compliant
ถ้า Age มี Type ชนิด UInt16 เมื่อ compile code เราจะได้ warning message ว่าผิดกฏ CLS-Compliant (ดู ตอนที่ 2 เพื่อความเข้าใจ)
3 กฏจะมีผลสำหรับ return Type และ parameter Type ของ method ที่เป็น public ของ Type ที่เป็นชนิด public
public class PersonController
{
public Int16 GetAge(int personID)
{
return 0;
}
private UInt16 getAge(UInt16 personID)
{
return 0;
}
public PersonController()
{
}
}
สำหรับตัวอย่าง code นี้ method getAge จะไม่มีผลกับกฏ CLS-Compliant แต่กับ method GetAge ที่เป็นชนิด public จะมีผลกับ CLS-Compliant.
4 กฏจะมีผลกับการ Type ที่มีการสืบทอด
กฏข้อนี้ก็ง่ายๆ เลยครับ Type ที่จะถูกสืบทอด C# compiler จะบังคับให้ class ชนิดนี้เป็น public อยู่แล้ว เมื่อ class เป็น public ตัว Type ก็จะต้องเข้าตามกฏ CLS-Compliant ข้อที่ 1
Type ที่แสดงข้างล่างจะเป็น Type ที่เป็น CLS-compliant
Byte unsigned interger ชนิด 8 บิต มีค่าได้ตั้งแต่ 0 ถึง 255
Int16 signed integer ชนิด 16 บิต มีค่าได้ตั้งแต่ -32,768 ถึง 32,767
Int32 signed integer ชนิด 32 บิต มีค่าได้ตั้งแต่ -2,147,483,648 ถึง 2,147,483,647
Int64 signed integer ชนิด 64 บิต มีค่าได้ตั้งแต่ -9,223,372,036,854,775,808 ถึง 9,223,372,036,854,775,807
Single จริงๆ ก็คือ Type float ในภาษา C# มีค่าได้ตั้งแต่ -3.4 × 1038 ถึง +3.4 × 1038
มีจุดทศนิยมได้ 7 หลัก
Double จริงๆ ก็คือ Type double ในภาษา C# มีค่าได้ตั้งแต่ ±5.0 × 10−324 ถึง ±1.7 × 10308 มีจุดทศนิยมได้ 15 หลัก
Boolean มีขนาด 1 byte เก็บได้แค่ค่า true กับ false
Char สำหรับเก็บตัวอักษรชนิด UTF-16
Decimal เก็บค่าได้เยอะมาก โดยสามารถใช้คำสั่ง desimal.MaxValue เพื่อดูค่ามากที่สุดที่สามารถเก็บได้และ decimal.MinValue เพื่อดูค่าน้อยที่สุดที่สามารถเก็บได้
IntPtr เก็บตำแหน่งของ pointer ในภาษา C# เราสามารถเล่นกับ pointer ได้เหมือนกันครับ เดียวจะเล่าให้ฟังในบทความหลังๆ ครับ
String เก็บตัวข้อความเป็นตัวหนังสือ
จะเห็นว่า float ไม่ได้เป็น Type ชนิด CLS-Compliant น่ะครับ ผมจะยกตัวอย่างในบทความหน้าครับ
พบกันใหม่ตอนหน้าครับ
TuChay
วันอังคารที่ 15 กันยายน พ.ศ. 2558
รู้จักกับ CLS ตอนที่ 2
บทความนี้มีการ reference มาจาก CLS Compliance ของ MSDN
เนื่องจาก CLS ของ Microsoft เป็นมาตรฐานสำหรับการพัฒนา software หรือ library เพื่อให้นักพัฒนาท่านอื่นสามารถนำไปใช้งานได้ ระหว่างที่เรากำลังพัฒนา library เราสามารถให้ compiler ตรวจสอบ code ที่เราเขียนขึ้นว่ารอบรับ CLS-compliant หรือไม่ ด้วยการระบุใน assembly ตามตัวอย่าง code ข้างล่าง
using System;
[assembly:CLSCompliant(true)]
namespace CLS
{
public class Person
{
public Person()
{
}
public Int32 Age
{
get { return 0; }
}
}
}
ถ้าเราเขียนโปรแกรมด้วย Visual Studio เราควรนำ [assembly:CLSCompliant(true)] ไปไว้ใน file AssemblyInfo.cs ภายใต้ folder Properties แต่ต้องจำไว้ว่า CLSCompliant เป็น member ของ namespace System จึงต้องมั่นใจว่าที่ file AssemblyInfo.cs มีการ using System; น่ะครับ
สำหรับตัวอย่าง code ข้างบนผมนำเอา [assembly:CLSCompliant(true)] มาไว้ที่ main code
จาก code เมื่อทำการ compile เราจะไม่ได้ warning message แต่ถ้าเปลี่ยน return type ของ property Age จาก Int32 เป็น UInt 16 ดัง code ข้างล่าง
public UInt16 Age
{
get { return 0; }
}
compiler สามารถ compile code และสร้าง manage file สำเร็จแต่ compiler จะ report warning message "Type of 'CLS-Person.Age' is not CLS-compliant" ตัวอย่างรูปข้างล่างน่ะครับ
สำหรับตัวอย่างนี้สาเหตุที่ไม่เป็น CLS-compliant เป็นเพราะว่าไม่ใช่ทุกภาษาที่จะรองรับ type UInt16 โดยเฉพาะภาษา VB.Net ดังนั้นถ้า class นี้ถูกนำไปใช้กับภาษา VB.Net ตัว property Age อาจจะใช้งานได้ไม่ถูกต้อง
แต่ถ้าเรามั่นใจว่า property Age สามารถใช้ได้กับทุกภาษาและต้องการ by pass การเช็ค CLS-compliant เฉพาะ property Age เราสามารถเขียน code ได้ดังนี้
[CLSCompliant(false)]
public UInt16 Age
{
get { return 0; }
}
แค่นี้เราก็สามารถ compile code โดยที่ไม่มี warning messageแล้วครับ แต่ไม่ควรทำน่ะ
พบกันใหม่ตอนหน้าตอนที่ 3 ครับ
TuChay
วันเสาร์ที่ 12 กันยายน พ.ศ. 2558
รู้จักกับ CLS ตอนที่ 1
บทความนี้มีการ reference มาจาก CLS Compliance ของ MSDN
จนมาถึงตอนนี้เราก็รู้จักกับ .Net Framework และภาษา IL กันมากขึ้น จากบทความ Common Type System ที่ผ่านมาผมได้อธิบายไปแล้วว่าเราสามารถที่จะเขียนภาษาเป็นของตัวเองได้ ในบทความชุดนี้จะเป็นการกล่าวถึงกฏการพัฒนา component software ที่เราต้องปฏิบัติตามอย่างเคร่งครัด
component software คือการพัฒนา software ชนิด library เพื่อให้นักพัฒนา software หรือ programmer ทีมอื่นเป็นคนเรียกใช้ ตัวอย่างของ component software เช่น driver library ของ hardware ที่เราพัฒนา hardware ชุดนั้นขึ้นมาเอง หรือ library สำหรับให้คนอื่นติดต่อกับ software system ด้วย Web Service เป็นต้น
จะเห็นว่า component software ที่เราพัฒนาขึ้น เราไม่สามารถระบุเจาะจงภาษาของนักพัฒนา software ที่เรียกใช้ library ของเราได้ ดังนั้นจึงเป็นไปได้ว่าคนที่เรียกใช้ library ที่เราพัฒนาจะพัฒนาด้วยภาษาที่หลายหลายและด้วยข้อกำหนดหรือรูปแบบของการเขียน code ของแต่ล่ะภาษาก็จะไม่เหมือนกัน เพื่อให้ component software หรือ library ของเราใช้ได้กับทุกๆ ภาษาของตะกูล .Net Framework ดังนั้น Microsoft จึงเขียนข้อกำหนด เกี่ยวกับการพัฒนา library ใส่ลงไปใน ECMA-335 หัวข้อ Stand Common Language Infrastructure โดยข้อกำหนดนี้ถูกกำหนดภายใต้ชื่อ CLS - Common Language Specification.
ในบทความชุดนี้จะเป็นการพูดถีงข้อปฏิบัติตามกฏของ CLS ซึ่งจะเป็นอะไรบ้างนั้น .... พบกันใหม่บทความหน้าครับ
TuChay
วันพฤหัสบดีที่ 10 กันยายน พ.ศ. 2558
Indexer ใน C# ตอนที่ 2
เรามาต่อจากตอนที่ 1 กันเลย
ในตอนที่แล้วผมได้เขียน code ที่ indexer มี signuature เป็น int อย่างเดียว ที่นี้เราลองเพิ่ม Indexer อีกหนึ่งตัวน่ะครับที่มี signature เป็น string.
public int this[string name]
{
get
{
for (int i = 0; i < 7; i++)
{
if (nameOfDay[i] == name)
return i;
}
return 99;
}
}
ใน IL code เราก็จะได้ method ที่ชื่อ get_Item อีกหนึ่งตัวแต่ signature ตัวใหม่จะเป็น get_Item : int32(string) คือรับ parameter เป็น string และ return int กลับไปให้ caller.
นอกจากนั้นเรายังจะได้ property อีกหนึ่งตัวที่ชื่อ Item : instance int32(string)
ต่อไปเราลองมาเพิ่ม C# code จาก read only มาเป็น property ที่สามารถ update ได้ ตาม code ข้างล่างครับ
public string this[int index]
{
get
{
if (index > nameOfDay.Length)
return "";
else
return nameOfDay[index];
}
set
{
if (index > nameOfDay.Length)
throw new Exception("The day should have only 7 day");
else
nameOfDay[index] = value;
}
}
จาก นั้นลอง compile code แล้วมาดู IL code กันครับจะเห็น method ที่เพิ่มเข้ามาอีก 1 method คือ set_Item : void(int 32, string) จะเห็นว่า signature จะเปลี่ยนมาเป็นรับค่า 2 parameter คือ int กับ string
โดยที่ parameter ชนิด int คือ ตำแน่งของ index และ string ก็คือ value ที่ assign ให้กับ index ตัวนั้น
จบแล้วครับสำหรับ Indexer ในภาษา C# และภาษา IL พบกันใหม่บทความหน้าครับ
TuChay
วันพุธที่ 9 กันยายน พ.ศ. 2558
Indexer ใน C# ตอนที่ 1
จาก code ของบทความ Common Type System ตอนที่ 2 ผมได้ยกตัวอย่าง method ชนิด indexer แต่ยังไม่ได้อธิบายอย่างละเอียด ผมขออธิบายรายละเอียดในบทความนี้น่ะครับ
Indexer คือ การดึงข้อมูลหรือ update ข้อมูลผ่าน instance object โดยใช้ index เป็น paremeter เรามาดูตัวอย่าง code กันครับ
class Program
{
static void Main(string[] args)
{
Weekly week = new Weekly();
for(int i=0;i<7;i++)
Console.WriteLine(week[i]);
Console.ReadLine();
}
}
public class Weekly
{
private string[] nameOfDay = new string[7] {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
public Weekly()
{
}
public string this[int index]
{
get
{
if (index > nameOfDay.Length)
return "";
else
return nameOfDay[index];
}
}
}
Indexer ของ class Weekly คือ public string this[int index] เราสามารถเรียกใช้ indexer ผ่าน object ได้เลยด้วย week[i] โดยที่ i ถือเป็น parameter ของ indexer นี้ครับ
เมื่อเรามาดู IL code จะได้ดังรูปข้างล่าง
C# compiler ได้สร้าง method ที่ชื่อ get_Item : string(int32)
string(int32) จะหมายถึง method นี้จะรับ parameter เป็น int32 และ method จะ return string กลับไปให้ caller
code ของ method สามารถเข้าไปดูได้โดยการ dobule click ที่บรรทัดนี้ ชื่อของ method C# compiler ตั้งชื่อตามหลักของ method คือนำ "get_" นำหน้า "Item" เพราะว่าเป็น method ชนิด indexer
เมื่อ เทียบกับภาษา C# method get_Item ก็คือ code นี้ครับ
public string this[int index]
{
get
{
if (index > nameOfDay.Length)
return "";
else
return nameOfDay[index];
}
}
นอกจากนั้น C# Compiler ยังได้สร้าง property ที่ชื่อ Item ใน บรรทัด Item : instance string(int32) เพื่อเป็นการสร้าง indexer สำหรับให้ caller เรียกใช้ เมื่อ double click ที่บรรทัดนี้ จะได้ดังรูป
เนื่องจาก Indexer Weekly ใน C# code ข้างบน เป็นการอ่านแบบ read only คือ ไม่มี คำสั่ง set มีแต่คำสั่ง get ใน IL code ของ property Item จึงมีแค่ .get เท่านั้น
พบกันใหม่ตอนที่ 2 ตอนหน้าครับ
TuChay
วันจันทร์ที่ 7 กันยายน พ.ศ. 2558
รู้จักกับ Shell บน Linux ตอนที่ 2
เรามาต่อจากตอนที่ 1 เลยน่ะครับ
ในช่วงนั้นระบบปฏิบัติการ Unix เป็น Open source แต่เรื่องของ license ยังเป็นสิ่งที่คลุมครือ และมีบางบริษัทนำระบบปฏิบัติการ Unix ที่เป็น Open source มาพัฒนาต่อเพื่อให้เป็น commercial version ของตัวเองและทำการออกจำหน่าย โดย commercial version ที่จำหน่ายก็ไม่เป็น open source อีกต่อไปซึ่งผิดวัตุประสงค์ของ Open source จึงทำให้เกิด project ที่ชื่อว่า GNU (Genernal public license) โดยผู้ก่อตั้งที่ชื่อ Richard Stallman
หนึ่งใน GNU project คือ Unix-compatible operating system ภายใต้ open sourcee และ free license จุดประสงค์หลักก็เพื่อเอามาแทนที่ Unix ที่มี license เป็นเชิงพาณิชย์ ใน project นี้ มีผู้ดูแลรับผิดชอบเกี่ยวกับ shell คือ Chet Ramey โดย shell ที่เขานำมาใช้ในระบบปฏิบัติการมีชื่อว่า Bourne Again Shell หรือ bash
bash version แรกถูกเขียนขึ้นโดย Brain Fox และถูก release ออกมาเมื่อวันที่ 10 มกราคม 1988 โดยการรวมเอาข้อดีหลักๆ ของ C shell และ Korn shell มาไว้รวมกันโดยพัฒนามาจาก code พื้นฐานของ Bourne shell และในปี 1989 Chet Ramey ได้ดึง Brain Fox เข้ามารวมทีมเพื่อที่จะนำ bash เป็น shell พื้นฐานของ Unix open source ที่เขาดูแลอยู่และในปัจจุปัน Chet Ramery เป็นผู้รับผิดชอบอย่างเป็นทางการในเรื่องของการแก้ bug และ improve feature ต่างๆ ของ bash เนื่องจาก bash เป็น shell แบบ free license จึงเป็นที่นิยมนำมาใช้เป็น shell มาตรฐานใน Linux หลายสายพันธุ์ รวมถึง Mac OS X ของ apple ด้วย
ในวันที่ 23 ธันวาคม 1996 Chet Ramey ได้ release bash version 2.0 (version ก่อนหน้านี้เป็น version 1.14.7) และ release version 3.0 ในวันที่ 27 กรกฏาคม 2004 จนกระทั่ง version ปัจจุปัน version 4 ที่ Chet Ramey ได้ release เมื่อวันที่ 20 กุมภาพันธ์ 2009
บทความต่อจากนี้ของผมจะพูดเกี่ยวกับการเขียน shell script บน bash เท่านั้นน่ะครับ
แล้วพบกันบทความหน้าครับ
TuChay
วันพฤหัสบดีที่ 3 กันยายน พ.ศ. 2558
รู้จักกับ Shell บน Linux ตอนที่ 1
ในยุคประมาณปี 1960 เป็นยุคเริ่มต้นของระบบ Unix และเป็นที่นิยมอย่างแพร่หลายในปี 1970 ในตอนนั้นเราแบ่งการทำงานของระบบ Unix เป็น 3 ส่วน คือ ส่วนที่เป็น input ส่วนที่ประมวลผล และส่วนที่เป็น output
ส่วนที่เป็น input กับส่วนที่เป็น output เป็นส่วนตรงกลางระหว่าง user หรือผู้ใช้กับหน่วยประมวลผล โดย input จะทำหน้าที่รับคำสั่งผ่านทาง keyboard แล้วแปลงคำสั่งนั้นส่งไปให้ ระบบปฏิบัติการ Unix เพื่อให้ CPU ประมวลผลและเมื่อได้ผลลัพท์ที่ได้จึงนำมาแสดงในส่วนที่ เป็น output นั้นคือ monitor นั้นเอง
ส่วนที่รับคำสั่งผ่านทาง keyboard แล้วแปลงคำสั่งเพื่อส่งไปให้ Unix ประมวลผลแล้วแสดงผลที่ได้ออกทาง monitor นี้แหละครับ เราเรียกว่า shell
ในสมัยนั้น Shell ที่ได้รับความนิยมมากที่สุดคือ Bourne shell version 7.0 สร้างและพัฒนาโดย Steven Bourne โดยเริ่มใช้ตั้งแต่ปี 1979 Bourne shell เราจะเขียนสั้นๆ ว่า sh
เนื่องจากโครงสร้างหรือรูปแบบคำสั่งของ sh เป็นคำสั่งง่ายและยังไม่สนับสนุนคำสั่งที่มีความซับซ้อน Bill Joy แห่งมหาวิทยาลัย Berkeley จึงได้พัฒนา Shell ใหม่ขึ้นเรียก C shell มีชื่อย่อว่า csh โดยรูปแบบคำสั่งของ shell จะมีลักษณะคล้ายกับภาษา C ทำให้นักพัฒนาที่มีความรู้ภาษา C สามารถสร้างสรรค์คำสั่งที่ซับซ้อนได้ดีขึ้นแต่ข้อเสียของ C Shell คือไม่ backward complitable กับ Bourne shell นั้นคือคำสั่งบางคำสั่งที่เคยใช้ได้ใน Bourne shell กับใช้ไม่ได้ใน C Shell.
หลังจากนั้นก็มี Shell เกิดขึ้นมาใหม่มากมายและเป็นที่นิยมใช้เช่น Korn Shell หรือตัวย่อ ksh โดย David Korn จาก AT&T โดยการรวมข้อดีของ C Shell และ Bourne shell เข้าด้วยกัน Korn shell สามารถ download ได้ฟรีแต่ผู้ download จะต้องจ่ายค่า license สำหรับบางสถาณการณ์
พบกันใหม่ตอนหน้าครับ
TuChay
วันพุธที่ 2 กันยายน พ.ศ. 2558
Common Type System (CTS) ตอนที่ 4 (ตอบจบ)
จาก code ตัวอย่างของ ตอนที่ 2 ในส่วนของตัวแปรชนิด event ของ C# code
public event EventHandler thisIsEvent;
code ข้างบนเมื่อถูก compile ด้วย C# compiler ตัว compiler จะสร้าง member ขึ้นมาทั้งหมด 4 ตัวในภาษา IL ดังรูปข้างล่าง
ตัวแรก คือ field ที่ชื่อ thisIsField (หมายเลข 1 ในรูป) โดย C# compiler จะสร้างเป็น member ชนิด private โดยมี type เป็นชนิด EventHandler ซึ่งเป็น type ที่อยู่ใน namespace System ของ MSCorLib.DLL
ตัวที่สองและสามคือ method ที่ชื่อ add_thisIsEvent (หมายเลข 2 ในรูป) กับ remove_thisIsEvent (หมายเลข 3 ในรูป) โดย C# compiler สร้าง method name โดยใส่ "add_" และ "remove_" รวมกับชื่อ field (หมายเลข 1 ในรูป)
ตัวที่สี่ คือสมาชิกชนิด event (หมายเลข 4 ของรูป) มี modifyer เป็นชนิด public สำหรับให้ caller เรียกใช้ ถ้าเรา double click ที่บรรทัดหมายเลข 4 ก็จะได้ ภาษา IL code ดังรูป
เมื่อ caller ทำการ subscribe event thisIsEvent ด้วย operator "+=" ตัว runtime ก็จะใช้คำสั่ง .addon เพื่อที่จะไปเรียก method add_thisIsEvent
และเมื่อ caller unsubscribe event thisIsEvent ด้วย operator "-=" ตัว runtime ก็จะใช้คำสั่ง .removeon เพื่อที่จะไปเรียก method remove_thisIsEvent
ลองดูตัวอย่าง code ที่ caller เรียกใช้ event thisIsEvent
static void Main(string[] args)
{
Program pg = new Program();
pg.thisIsEvent += new EventHandler(pg_thisIsEvent);
pg.thisIsEvent -= new EventHandler(pg_thisIsEvent);
}
static void pg_thisIsEvent(object sender, EventArgs e)
{
}
code pg.thisIsEvent += new EventHandler(pg_thisIsEvent); ณ ตอน runtime JITCompiler จะไปเรียกใช้คำสั่ง .addon ของ event thisIsEvent ซึ่งก็คือไปเรียกใช้ method add_thisIsField
สำหรับ code pg.thisIsEvent -= new EventHandler(pg_thisIsEvent); ณ ตอน runtime JITCompiler จะไปเรียกใช้คำสั่ง .removeon ของ event thisIsEvent ซึ่งก็คือไปเรียกใช้ method remove_thisIsField
จบแล้วครับสำหรับการแนะนำ type ทั้ง 4 ชนิดของภาษา IL พร้อมทั้งตัวอย่าง code ของ C# ถ้ามาถึงตอนนี้เราก็พอจะมีความรู้มากขึ้นในภาษา IL น่ะครับ จากตัวอย่าง code ของตอนที่ 2 ผมติดคำอธิบายเรื่องของ Indexer ซึ่งผมจะไปอธิบายพร้อมทั้งแสดงวิธีใช้ในอีกตอน
พบกันใหม่ตอนหน้าครับ
TuChay
สมัครสมาชิก:
บทความ (Atom)