0Pricing
C# Academy · บทเรียน

การเปิดใช้และทำความเข้าใจ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การเปิดใช้และทำความเข้าใจ NRT
  2. คำอธิบายประกอบ: ?, !, MaybeNull และ NotNull
  3. ตัวดำเนินการเงื่อนไข Null และรวมค่า Null
  4. การย้ายโค้ดเบสไปยัง NRT
← กลับไปที่ C# Academy