พอดีช่วงนี้ลองทวนสอบ เพื่อเตรียมสอบ Cert MCSD App Builder ของ Microsoft ครับ แล้วบังเอิญไปเจอ keyword อันนึงที่ กูรเขียน Code มาหลายปี ไม่เคยได้ยินเลย checked และ unchecked ครับ โดยก่อนเข้าไปรู้ว่า 2 คำนี้ มันมีความหมายอย่างไรใน C# เรามารู้จักกับ Exception ชนิดหนึ่งกันก่อนดีกว่าครับ
Arithmetic Overflow/Underflow คือ อะไร ?
สำหรับคอมพิวเตอร์เวลามันทดอะไรบางอย่าง เราจะเก็บที่หน่วยความจำ แล้วที่นี่ในการเขียนโปรแกรมตอนที่เราจะทดค่าต่างๆนั้น มันมีภาชนะให้เก็บหลายรูปแบบ ซึ่งพื้นฐานของคอมพิวเตอร์มาจากคณิตศาสตร์ การที่เราจะเก็บอะไรลงภาขนะ แต่ละแบบ มันมีข้อจำกัด นัั่นก็ช่วง หรือขอบเขตที่สามารถรับได้ ถ้าสรุปในภาษา Dev มันบอกว่า Data Type(ภาชนะ) ซึ่งแต่ละแบบ เช่น int, float Decimal หรือ String มันมีข้อจำกัด หรือขอบเขต ที่บอกว่าเราสามารถเก็บอะไรลงไปได้ และได้เท่าไหร่ มี min-max นั้นเองครับ ถ้าลองดูใน C# ค่า min และ max ของ DataType บางชนิดมา มีค่า min/max นะครับ ดังนี้ครับ
short.MaxValue : 32767 short.MinValue : -32768 ushort.MaxValue : 65535 ushort.MinValue : 0 int.MaxValue : 2,147,483,647 int.MinValue : -2,147,483,648 uint.MaxValue : 4,294,967,295 uint.MinValue : 0 long.MaxValue : 9,223,372,036,854,775,807 long.MinValue : -9,223,372,036,854,775,808
แล้ว Overflow กับ Underflow คือ อะไรหละ ?
- Overflow คือ การคำนวณต่างๆ แล้วผลลัพธ์ที่ได้มันมีค่ามากกว่าที่ตัวแปรชนิดนั้นๆ จะเก็บค่าได้ครับ (สั้นๆ ค่าเกิน max)
- Underflow คือ การคำนวณต่างๆ แล้วผลลัพธ์ที่ได้มันมีค่าน้อยกว่าที่ตัวแปรชนิดนั้นๆ จะเก็บค่าได้ครับ (สั้นๆ ค่าน้อยกว่า min)
OverflowException คือ อะไร ?
Exception ข้อผิดพลาด ที่เราสามารถจัดการได้ สำหรับในกรณีนี้ คือ ข้อมูลที่คำนวณได้ มันล้นเกิน(Overfllow) ออกมาจากจากภาชนะที่เก็บไว้ (ตัวแปร) ถ้าดูโครงสร้าง OverflowException พบว่ามันเป็น Type หนึ่งของ System.ArithmeticException ครับ
checked & unchecked
หลังจากรู้จักกับ Arithmetic Overflow Exception แล้ว กลับมาที่ตัว C#กันก่อนครับ ว่าตัวภาษามันมีอะไรช่วยเรา หรือป่าว คำตอบ คือ มีครับ แต่ปกติไม่เปิดไว้ (ค่า Default = unchecked) แต่มีคำสั่งเข้ามาจัดการเรื่องนี้ 2 คำสั่งครับ ได้แก่
- checked - บอกว่า Code ที่อยู่ในส่วนของ คำสั่ง checked มีการตรวจสอบ พวก Overflow/Underflow ครับ ถ้าดูจาก Code เป็น Code ที่ผมใช้คำนวณดอกเบี้ยของพันธบัตร/หุ้นกู้(Bond) ครับ
public class BondCalculation { //Some Business Logic public Decimal CalcInterest() { checked { /* Some Interest Calc Logic ... Some Interest Calc Logic */ return Interest } } }
- unchecked - บอกว่า Code ที่อยู่ในส่วนของ คำสั่ง unchecked ไม่มีการตรวจสอบ พวก Overflow/Underflow ครับ อ้าวแล้วกรณีไหนที่ต้องไม่ Check หละ การคำนวณด้าน การเงิน คงไม่ใช่แน่ๆ เงินหาย คงไม่มีใครยอมอยู่แล้วครับ แต่มีบางอัลกอริทึมนะ ที่ไม่ได้สนใจค่าของมัน(magnitude) อย่าง เช่น การทำ Hash ครับ
[Serializable] public abstract class MasterDTO : RepositoryDTO { //Some Logic public override int GetHashCode() { unchecked { //Sample Logic int hashCode = 17; hashCode = hashCode * 19 + (Id == null ? 0 : Id.GetHashCode()); hashCode = hashCode * 19 + (CreateTime == null ? 0 : CreateTime.GetHashCode()); //Sample Logic //Note: your can add you logic for calculating hash code return hashCode; } } }
Note:
- สำหรับตอนนี้ใน C# ยังไม่มี UnderflowException ครับ ถ้าเกิด Exception ในกรณีนี้จริงๆ ระบบจะโยนตัว InvalidOperationException มาแทนครับ
- คำสั่ง checked / unchecked มี ขอบเขตแบบ Local ถ้าในขอบเขตดันไปมีการเรียกใช้ Method อื่น ตัว Method อื่น ไม่เข้าข่ายนะครับ ตามตัวอย่าง พบว่า Method CalcSomethingOverflows ไม่เข้าขอบเขตของคำสั่ง checked ครับ
public class TestChecked { public void TestOverflow() { checked { // this method will execute in unchecked context CalcSomethingOverflows(); } } public void CalcSomethingOverflows() { // no overflow exception chekcibng (thrown)... var overflowed = Decimal.MaxValue + 1; } }
- คำสั่ง try-catch มันก็ไม่ได้สนใจพวก Overflow และ Underflow ครับ โดยจากตัวอย่าง Code สังเกตุว่า Method dependsonDefault ปล่อยให้คำตอบเป็นไปตามยถากรรมครับ ซึ่งสามารถทำงานได้ด้วย แต่ถูก หรือป่าวอีกเรื่องนะครับ แต่หากมีคำสั่ง Checked ไว้ ตามใน Method checkedMethod มันจะ throw exception ทันทีครับ
using System; class Test { static readonly int x = 1000000; static readonly int y = 1000000; static int checkedMethod() { return checked(x * y); // Throws OverflowException } static int uncheckedMethod() { return unchecked(x * y); // Returns -727379968 } static int dependsonDefault() { return x * y; // Depends on default } public static void Main() { Console.WriteLine(); try { Console.WriteLine("Call uncheckedMethod - Can execute and not throw exception"); Console.WriteLine(Test.uncheckedMethod()); Console.WriteLine("=========================================="); Console.WriteLine("Call dependsonDefault - Can execute and not throw exception"); Console.WriteLine(Test.dependsonDefault()); Console.WriteLine("=========================================="); } catch(Exception ex) { Console.WriteLine(ex); } Console.WriteLine("Call checkedMethod - Can not execute and throw exception"); Console.WriteLine(Test.checkedMethod()); Console.WriteLine("=========================================="); } }
- ผลลัพธ์การ Run ของ Code ตัวอย่าง try-catch ครับ
โห ถ้าจะต้องการให้มันตรวจสอบทั้ง Project นีไม่ต้องไล่ใส่คำสั่ง Checked ไปจนพรุนทั้ง Solution/Project เลยเหรอ คำตอบ คือ ว่ามีครับ ถ้าให้ในมัน Defaultให้มีค่าเป็น checked ตั้งแต่ต้นให้ไปกำหนดค่าใน Project ดังรูปครับ
ถ้าตรงไหนไม่เอา ก็สามารถใช้คำสั่ง unchecked มากำหนดแทนครับ
Reference
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.