Dynamic vs Object Type ใน C#
ทั้งคู่สามารถเก็บค่าได้ทุกชนิด แต่ **เวลาที่ตรวจสอบชนิด (Type Checking)** และ **ความสามารถ** ต่างกัน
object Type (System.Object)
- Base class ของทุก Type ใน .NET (Common Type System)
- **Static Typing** - ตรวจสอบชนิดข้อมูล **Compile-time**
- ต้อง **Cast** (Boxing/Unboxing) เพื่อใช้งานสมาชิกเฉพาะชนิด
- Performance: Boxing/Unboxing overhead สำหรับ Value Types
object obj = 100; // Boxing (int → object)
object str = "Hello"; // Reference assignment
object list = new List();
// ต้อง Cast เพื่อใช้งาน
int num = (int)obj; // Unboxing - throw InvalidCastException ถ้าผิด
string s = (string)str;
// ใช้ with pattern matching (C# 7+)
if (obj is int i) Console.WriteLine(i);
switch (obj)
{
case int i: Console.WriteLine($"Int: {i}"); break;
case string st: Console.WriteLine($"String: {st}"); break;
}
dynamic Type (C# 4.0+)
- **Dynamic Typing** - ตรวจสอบชนิดข้อมูล **Runtime** (DLR - Dynamic Language Runtime)
- **ไม่ต้อง Cast** - เรียก Member ใดๆ ได้ (Method, Property, Operator)
- Error จะเกิด **Runtime** (RuntimeBinderException) ไม่ใช่ Compile-time
- รองรับ COM Interop, Dynamic Languages (IronPython), JSON, XML
dynamic dyn = 100;
dyn = "Hello";
dyn = new List { 1, 2, 3 };
// เรียก member ได้เลย ไม่ต้อง cast
Console.WriteLine(dyn.Count); // 3 (List.Count)
Console.WriteLine(dyn.Length); // RuntimeBinderException! (List ไม่มี Length)
dyn.Add(4); // เรียก Method ได้
dyn.NonExistentMethod(); // RuntimeBinderException
// Dynamic กับ Anonymous Type
dynamic anon = new { Name = "John", Age = 30 };
Console.WriteLine(anon.Name); // "John" - ไม่ต้อง reflection!
ตารางเปรียบเทียบ
| คุณสมบัติ | object | dynamic |
|---|---|---|
| Type Checking | Compile-time (Static) | Runtime (Dynamic) |
| IntelliSense/IDE Support | เต็มรูปแบบ | ไม่มี (Unknown at compile time) |
| Performance | เร็ว (Direct/Boxing) | ช้ากว่า (DLR Call Site Cache) |
| Boxing/Unboxing | Value types ต้อง Boxing | Internal boxing แต่จัดการให้ |
| Member Access | ต้อง Cast/Reflection | เรียกได้เลย (Runtime resolve) |
| Error Detection | Compile-time | Runtime (RuntimeBinderException) |
| Inheritance | Base class ของทุกอย่าง | ไม่ใช่ Type จริง (Compiler trick) |
เมื่อไหร่ควรใช้ dynamic?
- Interop กับ Dynamic Languages (Python, JavaScript via JS engines)
- COM Objects (Office Automation, Windows Scripting)
- JSON/XML Parsing แบบไม่มี Schema คงที่
- Reflection-heavy code ทำให้สั้นลง
- Duck Typing scenarios
เมื่อไหร่ควรใช้ object?
- General purpose "any type" container
- ต้องการ Compile-time safety
- Performance critical
- Pattern matching (C# 7+) ทำงานได้ดีกับ object
ตัวอย่าง: JSON Parsing
// ใช้ dynamic กับ Newtonsoft.Json / System.Text.Json
string json = @"{ ""name"": ""John"", ""age"": 30, ""active"": true }";
// System.Text.Json (C# 10+)
dynamic data = System.Text.Json.JsonSerializer.Deserialize(json);
Console.WriteLine(data.name); // John - ไม่ต้อง define class!
Console.WriteLine(data.age); // 30
// แต่ถ้าผิด property name
// Console.WriteLine(data.nmae); // RuntimeBinderException ไม่ใช่ Compile error
ExpandoObject - Dynamic Object แบบเพิ่ม Member ได้
using System.Dynamic;
dynamic expando = new ExpandoObject();
expando.Name = "Dynamic";
expando.Age = 25;
expando.SayHello = new Action(() => Console.WriteLine($"Hi {expando.Name}"));
expando.SayHello(); // Hi Dynamic
// เพิ่ม property ได้ตลอด
expando.Country = "Thailand";
สรุป
object = Safe, Fast, Compile-time checking, ต้อง Cast
dynamic = Flexible, Late-binding, Runtime errors, ใช้ตอนจำเป็นจริงๆ