protect

ถ้าเอาบทความไปเผยแพร่แล้วไม่ให้เครดิต ดำเนินคดีด้วย พรบ. คอมพิวเตอร์ฉบับใหม่ ขั้นสูงสุดและไม่ยอมความครับ

วันจันทร์ที่ 12 ตุลาคม พ.ศ. 2558

Assembly Module : ตอนที่ 2 จาก Type สู่ Assembly Module


เราได้เรียนรู้แล้วว่าการเขียนโปรแกรมด้วยภาษาในตระกูลของ ,Net Framework ซึ่งมีกฏของ CTS ระบุไว้ว่าใน 1 program จะต้องมีอย่างน้อย 1 Type หรือ 1 class การแปลงจาก Type มาเป็น assembly module เป็นยังไง เรามาลองดูตัวอย่าง code ง่ายๆ ตาม code ข้างล่างน่ะครับ

using System;

public class Program
{
    public static void Main()
    {
            System.Console.WriteLine("Hello World");
   
    }
}

code ข้างบนให้เขียนด้วยโปรแกรม notepad แล้ว save เป็น file ชื่อ Program.cs ที่ผมให้เขียนด้วยโปรแกรม notepad เพราะในบทความถัดไปผมจะอธิบายเรื่อง .netmodule ซึ่ง VisualStudio ไม่อนุญาติให้ compile code เป็น .netmodule เฉพาะคำสั่ง csc เท่านั้นที่อนุญาติ

จากนั้นเปิดโปรแกรม Command Prompt ของ Visual Studio .Net ตามรูปน่ะครับ





แล้วก็เริ่ม compile code ด้วยคำสั่ง

          csc.exe /out:Program.exe /t:exe /r:MSCorLib.dll Program.cs

คำสั่ง csc.exe เป็นคำสั่งของ C# compiler โดยมีรายละเอียดของพารามิเตอร์ดังต่อไปนี้

 /out:Program.exe (/out = output) เพื่อให้ compiler สร้าง execute file ที่ชื่อ Program.exe

/t:exe (/t = target) โดยปกติ C# compiler แบ่งโปรแกรม execute file ที่ใช้บน Windows ออกเป็น 2 ชนิดได้แก่ GUI (graphisl user interface) และ CUI (Console user interface)
พารามิเตอร์ /t:exe จะเป็นการ compiler ให้ comiple code แล้วสร้าง execute file ในรูปแบบ CUI ( Console user interface)
พารามิเตอร์ /t:winexe  จะเป็นการบอก compiler ให้ compile เป็นแบบ GUI (graphical user interface)
พารามิเตอร์ /t:library จะเป็นการบอก compiler ให้ compile เป็นแบบ library

พารามิเตอร์ /t:exe และ พารามิเตอร์ /t:winexe C# compiler จะสร้าง entry point ลงไปใน CLR Healder ด้วย ดังนั้นตัว code จำเป็นต้องมี function Main อยู่เสมอ

/r:MSCorLib.dll (/r = reference) เนื่องจากใน code มีการใช้ Type System.Console ซึ่งเป็น library มาตรฐานอยู่ใน MSCorLib.dll เราจึงต้องมีการ บอกให้ compiler ทำการ reference Type ภายใน library MSCorLib.dll

เนื่องจาก Type ที่เป็นพื้นฐานต่างๆ เช่น int byte double ต่างเป็น Type ที่อยู่ใน library MSCorLib.dll และทุกๆ โปรแกรมส่วนใหญ่จะมีการใช้ที่บ่อยครั้ง ดังนั้น C# compiler ก็จะอัตโนมัติ reference ไปที่ library นี้ โดยที่ ไม่จำเป็นต้องระบุ /r:MSCorLib.dll ก็ได้

defaul target ของ C# Compiler เป็น CUI รวมทั้ง default output file name ก็เป็นชื่อเดียวกับชื่อ file ของ source code (ในตัวอย่างคือ Program.cs) ดังนั้นเราจึงตัด พารามิเตอร์ /t:exe และ พารามิเตอร์ /out:Program.exe ออกไปได้เช่นกัน

ดังนั้น เมื่อต้องการ compile code ก็สามารถเขียนสั้นๆ ได้เป็น

                   csc.exe Program.cs

สำหรับคำสั่ง csc ยังมี พารามิเตอร์อีกหนึ่งตัวคือ /nostdlib สำหรับกรณีที่เราไม่ต้องการใช้ standard library ของ .Net Framework หมายความเราทำ library ของตัวเองขึ้นมาทั้งหมด ดังนั้นการใช้ /nostdlib เมื่อ compile code ไปแล้วเราจะได้ managed module และยังเป็น Assembly Module ในตัวเดียวกัน

แต่จาก code ตัวอย่างจะเห็นว่า Program.cs ไม่สามารถทำงานได้ด้วยตัวเองยังต้องใช้ standard library ของ .Net Framework  ดังนั้นตัวโครงสร้างของ execute file Program.exe ในส่วนของ metadata (metadata เป็นตัวเก็บข้อมูลของ Type ที่ผมได้อธิบายคร่าวๆ แล้วที่ บทความนี้) จึงเป็นตัวทำให้ Program.exe กลายเป็น Assembly Module

metadata ผมจะอธิบายอย่างละเอียดในบทความถัดไปครับ

พบกันใหม่บทความหน้าครับ
TuChay

วันพฤหัสบดีที่ 1 ตุลาคม พ.ศ. 2558

Assembly Module : ตอนที่ 1 บทนำ


บทความที่ผ่านมาผมได้แนะนำให้รู้จักกับ Managed Module กันมาแล้ว ซึ่งใน Managed module จะมีทั้งหมด 4 ส่วนคือ PE, CLR Header, Metadata และ IL language แต่จริงๆแล้วโปรแกรมที่เราเขียนขึ้นจะทำงานได้ไม่ใช่แค่ Managed module เพราะโปรแกรมจะมีการเรียกใช้ library พื้นฐาน ต่างๆของ .Net framework เช่น int หรือ string ซึ่งเป็น Type ที่อยู่ใน namespace System ของ MSCorelib.dll

การทำงานรวมกันระหว่างโปรแกรมที่เราเขียนและ library อื่นๆ ไม่ว่าจะเป็นของ .Net framework หรือ library ของคนอื่นๆ จะทำงานร่วมกันภายใต้ Assembly module ที่ผมกำลังจะอธิบายต่อจากนี้

เนื่องจากผมจะพยายามอธิบายในเรื่องของหลักการ ดังนั้นตัวอย่างการเขียน code จะเน้นไปที่เขียน code ด้วย notepad และการ compile code ก็จะใช้คำสั่ง csc ผ่าน command เพราะว่า Visual Studio มี option ที่ให้นักพัฒนาสามารถ config compiler ได้โดยที่ไม่ต้องรู้รายละเอียดมากนัก จนทำให้เราขาดความรู้ความเข้าใจอย่างลึกซึ้งเกี่ยวกับ .Net framework ผมหวังว่าบทความต่อไปนี้ผู้อ่านจะเข้าใจหลักการพื้นฐาน ของ .Net framework มากขึ้นครับ

พบกันใหม่บทความหน้าครับ
TuChay

วันจันทร์ที่ 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 



Type ชนิด double ในภาษา C# จะถูกแปลงเป็น Type float64 ใน IL ถ้าอยากใช้ Type double ในภาษา IL จะต้องใช้คำสั่ง [mscorlib]System.Double 

เมื่อเรา 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