การเปิดใช้และทำความเข้าใจ NRT
เปิดใช้บริบทที่รองรับค่า null ทำความเข้าใจชนิดอ้างอิงที่เป็น nullable และ non-nullable และอ่านคำเตือนจากคอมไพเลอร์
การเปิดใช้และทำความเข้าใจ NRT เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความผิดพลาดมูลค่าพันล้านดอลลาร์
Tony Hoare ผู้คิดค้นค่าว่าง เรียกสิ่งนี้ว่า 'ความผิดพลาดมูลค่าพันล้านดอลลาร์' ใน C# ชนิดการอ้างอิงใด ๆ อาจเป็นค่าว่างได้โดยค่าเริ่มต้น ทำให้ NullReferenceException เป็นสาเหตุที่พบบ่อยที่สุดของการขัดข้องขณะทำงาน ชนิดการอ้างอิงที่อาจเป็นค่าว่าง (NRT) แก้ปัญหานี้ตั้งแต่ระดับคอมไพเลอร์
การเปิดใช้บริบทค่าว่าง
เปิดใช้ NRT ทั่วทั้งโปรเจกต์ในไฟล์โปรเจกต์ หรือเปิดใช้แยกเป็นรายไฟล์ด้วยคำสั่ง เมื่อเปิดใช้แล้ว คอมไพเลอร์จะถือว่าชนิดการอ้างอิงไม่เป็นค่าว่างโดยค่าเริ่มต้น
<!-- In .csproj — enable for the whole project -->
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
// Or per-file:
#nullable enable
// ... code with NRT warnings
#nullable disable
// ... code without NRT warningsชนิดการอ้างอิงที่ไม่เป็นค่าว่างกับชนิดการอ้างอิงที่อาจเป็นค่าว่าง
เมื่อเปิดใช้ NRT: string หมายถึงค่า ไม่มีวันเป็นค่าว่าง ส่วน string? หมายถึงค่า อาจเป็นค่าว่าง คอมไพเลอร์จะแจ้งเตือนเมื่อคุณกำหนดค่าว่างให้ชนิดที่ไม่เป็นค่าว่าง หรือเข้าถึงค่าที่ nullable โดยไม่ตรวจสอบก่อน
#nullable enable
string nonNull = "Hello"; // OK
string? maybeNull = null; // OK — explicitly nullable
nonNull = null; // WARNING: CS8600
Console.WriteLine(maybeNull.Length); // WARNING: CS8602 — may be null
// Fix:
if (maybeNull is not null)
Console.WriteLine(maybeNull.Length); // safeการวิเคราะห์การไหลของข้อมูล
คอมไพเลอร์ทำ การวิเคราะห์การไหลของข้อมูล โดยติดตามสถานะค่าว่างผ่านเงื่อนไขและแขนงต่าง ๆ และระงับคำเตือนเมื่อพิสูจน์ได้ว่าค่าไม่เป็นค่าว่าง
string? name = GetName();
// After null check, name is treated as non-null:
if (name is not null)
Console.WriteLine(name.Length); // no warning
// Same with early return:
if (name is null) return;
Console.WriteLine(name.Length); // no warning — null was returned
// Pattern matching:
if (name is string s)
Console.WriteLine(s.ToUpper()); // no warningคำเตือนเกี่ยวกับค่าว่าง: CS8600–CS8629
คำเตือน NRT สำคัญที่ควรทำความเข้าใจ ได้แก่ CS8600 (กำหนดค่าว่างให้ชนิดที่ไม่เป็นค่าว่าง), CS8602 (เข้าถึงค่าที่อาจเป็นค่าว่าง), CS8603 (คืนค่าว่างให้ชนิดที่ไม่เป็นค่าว่าง) และ CS8618 (ฟิลด์ชนิดที่ไม่เป็นค่าว่างยังไม่ได้เริ่มต้นค่า)
#nullable enable
public class Order
{
public string CustomerName { get; set; } // CS8618: not initialized
public string? TrackingNumber { get; set; } // OK — nullable
public Order(string name)
{
CustomerName = name; // now initialized — CS8618 gone
}
}
string? s = GetValue();
Console.WriteLine(s.Length); // CS8602: s might be nullการเริ่มต้นค่าฟิลด์ที่ไม่เป็นค่าว่าง
CS8618 จะเกิดขึ้นเมื่อไม่ได้กำหนดค่าฟิลด์หรือคุณสมบัติที่ไม่เป็นค่าว่างในตัวสร้าง วิธีแก้ไขมีดังนี้: เริ่มต้นค่าในส่วนประกาศ บังคับให้กำหนดค่าผ่านตัวสร้าง หรือใช้ตัวดำเนินการยืนยันว่าไม่เป็นค่าว่างสำหรับรูปแบบ DI/ORM
// Option 1: Initialize in declaration
public string Name { get; set; } = "";
// Option 2: Require via constructor
public class Product
{
public string Name { get; }
public Product(string name) => Name = name;
}
// Option 3: null-forgiving for ORM entities
public string Name { get; set; } = null!;
// null! tells compiler "trust me, this will be set by EF Core"Nullable ในชนิดข้อมูลทั่วไป
พารามิเตอร์ของชนิดข้อมูลทั่วไปสามารถกำหนดข้อจำกัดให้ไม่เป็นค่าว่างได้ ข้อจำกัด where T : notnull รับรองว่า T ไม่มีวันเป็นค่าว่าง
// Without constraint: T could be nullable
public T? Find<T>(int id) { ... }
// With notnull: T must be a non-nullable type
public T FindRequired<T>(int id) where T : notnull
{
var result = InternalFind<T>(id);
return result ?? throw new KeyNotFoundException();
}
// T? is meaningful only when T is known to be non-nullable
public T? FindOrDefault<T>(int id) where T : class { ... }Nullable ในอินเทอร์เฟซและการเขียนทับ
เมื่อใช้งานอินเทอร์เฟซหรือเขียนทับเมธอด คำกำกับการอนุญาตค่าว่างต้องสอดคล้องกัน คอมไพเลอร์จะตรวจสอบว่าการใช้งานนั้นไม่เป็นค่าว่างอย่างน้อยเท่าที่อินเทอร์เฟซประกาศไว้
public interface IRepository<T>
{
T? FindById(int id); // may return null
T GetOrThrow(int id); // never null
}
// Implementation:
public class ProductRepo : IRepository<Product>
{
public Product? FindById(int id) => _db.Find(id);
public Product GetOrThrow(int id) =>
_db.Find(id) ?? throw new KeyNotFoundException();
}ชนิดค่าที่อาจเป็นค่าว่างกับชนิดการอ้างอิงที่อาจเป็นค่าว่าง
อย่าสับสนระหว่าง int? (Nullable<int> — ตัวห่อชนิดค่าที่มีอยู่ก่อน C# 8) กับ string? (คำกำกับ NRT — มีผลเฉพาะขณะคอมไพล์และไม่มีค่าใช้จ่ายเพิ่มเติมขณะทำงาน)
// Nullable value type (runtime Nullable<int>)
int? age = null;
bool hasValue = age.HasValue;
int value = age.GetValueOrDefault();
// Nullable reference type (compile-time annotation only)
string? name = null;
// string? has NO runtime wrapper — it's just a compile-time hint
// null check is still needed at runtime
if (name is not null)
Console.WriteLine(name.ToUpper());การระงับคำเตือนด้วย !
ตัวดำเนินการยืนยันว่าไม่เป็นค่าว่าง (!) ใช้ระงับคำเตือนเกี่ยวกับค่าว่างเฉพาะจุดเมื่อคุณทราบข้อมูลมากกว่าคอมไพเลอร์ ควรใช้เท่าที่จำเป็นและอธิบายเหตุผลที่มั่นใจว่าปลอดภัย
// Use ! when you know the value cannot be null
var user = _db.Users.FirstOrDefault(u => u.Email == email);
var name = user!.Name; // user is guaranteed by business logic
// EF Core navigation properties set by the framework:
public class Order
{
public Customer Customer { get; set; } = null!; // set by EF Core
}ตัวอย่างจริง: การตอบกลับ API ที่อาจเป็นค่าว่าง
ตัวห่อ API ที่ฟิลด์ต่าง ๆ อาจมีหรือไม่มีอยู่ในการตอบกลับ JSON คำกำกับการอนุญาตค่าว่างช่วยสื่อเจตนาได้อย่างชัดเจน
#nullable enable
public class WeatherResponse
{
public string City { get; set; } = ""; // always present
public double Temperature { get; set; } // always present
public string? Description { get; set; } // optional field
public string? AlertMessage { get; set; } // only when there's an alert
}
// Consumer:
var weather = await api.GetWeatherAsync("London");
Console.WriteLine(weather.City); // safe
Console.WriteLine(weather.Description?.ToUpper() ?? "N/A"); // safe null-handlingตรวจสอบความเข้าใจอย่างรวดเร็ว
ชนิดการอ้างอิงที่อาจเป็นค่าว่าง (string?) มีค่าใช้จ่ายเพิ่มเติมขณะทำงานเท่าใดเมื่อเทียบกับชนิดการอ้างอิงปกติ (string)
สรุป: การเปิดใช้และทำความเข้าใจ NRT
ประเด็นสำคัญ:
- เปิดใช้ทั่วทั้งโปรเจกต์ด้วย
<Nullable>enable</Nullable>ใน .csproj string= ไม่มีวันเป็นค่าว่าง;string?= อาจเป็นค่าว่าง- การวิเคราะห์การไหลของข้อมูลจะติดตามสถานะค่าว่างผ่านแขนงและค่าที่คืนกลับ
- คำกำกับ NRT มีผลเฉพาะขณะคอมไพล์เท่านั้น — ไม่มีค่าใช้จ่ายเพิ่มเติมขณะทำงาน
- CS8618: เริ่มต้นค่าฟิลด์ที่ไม่เป็นค่าว่างในตัวสร้าง หรือใช้
= null!สำหรับ ORM - ใช้ ! เท่าที่จำเป็น และอธิบายเหตุผลที่ตัวดำเนินการยืนยันว่าไม่เป็นค่าว่างปลอดภัย
คำถามที่พบบ่อย
บทเรียน “การเปิดใช้และทำความเข้าใจ NRT” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเปิดใช้และทำความเข้าใจ NRT” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเปิดใช้และทำความเข้าใจ NRT”
เปิดใช้บริบทที่รองรับค่า null ทำความเข้าใจชนิดอ้างอิงที่เป็น nullable และ non-nullable และอ่านคำเตือนจากคอมไพเลอร์ คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การเปิดใช้และทำความเข้าใจ NRT” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การเปิดใช้และทำความเข้าใจ NRT
- คำอธิบายประกอบ: ?, !, MaybeNull และ NotNull
- ตัวดำเนินการเงื่อนไข Null และรวมค่า Null
- การย้ายโค้ดเบสไปยัง NRT