พอดีช่วงนี้ลองทวนสอบ เพื่อเตรียมสอบ Cert MCSD App Builder ของ Microsoft ครับ แล้วบังเอิญไปเจอ keyword อันนึงที่ กูรเขียน Code มาหลายปี ไม่เคยได้ยินเลย checked และ unchecked ครับ โดยก่อนเข้าไปรู้ว่า 2 คำนี้ มันมีความหมายอย่างไรใน C# เรามารู้จักกับ Exception ชนิดหนึ่งกันก่อนดีกว่าครับ
Table of Contents
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.



