0Pricing
C# Academy · درس

تمكين NRT وفهمه

فعّلوا سياق nullable، وافهموا أنواع المراجع nullable وغير nullable، واقرؤوا تحذيرات المترجم.

تمكين NRT وفهمه درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.

الخطأ الذي كلّف مليار دولار

وصفه Tony Hoare (مخترع null) بأنه «خطؤه الذي كلّف مليار دولار». في C#، يمكن أن تكون أي قيمة من نوع مرجعي null افتراضيًا، مما يجعل NullReferenceException أكثر أعطال وقت التشغيل شيوعًا. تعالج أنواع المراجع القابلة لـ null (NRT) هذه المشكلة على مستوى المترجم.

تمكين سياق Nullable

مكّن NRT على مستوى المشروع في ملف المشروع، أو لكل ملف باستخدام التوجيهات. بعد تمكينه، يتعامل المترجم مع أنواع المراجع على أنها غير قابلة لـ null افتراضيًا.

<!-- 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

أنواع المراجع غير القابلة لـ null والقابلة لـ null

عند تمكين NRT: تعني string أن القيمة لا يمكن أن تكون null مطلقًا، بينما تعني string? أنها قد تكون null. يصدر المترجم تحذيرًا عند إسناد null إلى نوع غير قابل لـ null أو إلغاء الإشارة إلى نوع قابل لـ null دون إجراء تحقق.

#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

تحليل تدفق القيم

يجري المترجم تحليلًا لتدفق القيم — إذ يتتبع حالة null عبر الشروط والفروع، ويمنع التحذيرات عندما يستطيع إثبات أن القيمة ليست null.

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

تحذيرات Nullable: CS8600–CS8629

من أهم تحذيرات NRT التي ينبغي فهمها: CS8600 (إسناد null إلى نوع غير قابل لـ null)، وCS8602 (إلغاء الإشارة إلى قيمة قد تكون null)، وCS8603 (إرجاع null لنوع غير قابل لـ null)، وCS8618 (حقل غير قابل لـ null لم تتم تهيئته).

#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

تهيئة الحقول غير القابلة لـ null

يظهر CS8618 عندما لا يُعيَّن حقل أو خاصية غير قابلة لـ null في المُنشئ. وتشمل الحلول تهيئتها عند التصريح، أو اشتراطها عبر المُنشئ، أو استخدام عامل تجاهل null في أنماط 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 في الأنواع العامة

يمكن تقييد معلمات الأنواع العامة بحيث لا تقبل القيم null. ويضمن القيد where T : notnull ألا تكون T مساوية لـ null مطلقًا.

// 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 في الواجهات وعمليات التجاوز

عند تنفيذ واجهة أو تجاوز أسلوب، يجب أن تتطابق تعليقات قابلية null. يتحقق المترجم من أن عمليات التنفيذ ليست أقل قابلية لـ null مما تصرّح به الواجهة.

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();
}

أنواع القيم Nullable مقابل أنواع المراجع Nullable

لا تخلط بين 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());

منع التحذيرات باستخدام !

يمنع عامل تجاهل null (!) تحذيرًا محددًا متعلقًا بـ Nullable عندما تكون لديك معرفة أفضل من المترجم. استخدمه باعتدال ووثّق سبب أمانه.

// 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 قابلة لـ null

غلاف API قد تكون بعض حقوله موجودة أو غير موجودة في استجابة JSON — وتوضح تعليقات قابلية null الغرض بوضوح.

#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

تحقق سريع

ما تكلفة وقت التشغيل لأنواع المراجع القابلة لـ null (string?) مقارنةً بأنواع المراجع العادية (string)؟

مراجعة: تمكين NRT وفهمه

أهم النقاط:

  • مكّنه على مستوى المشروع باستخدام <Nullable>enable</Nullable> في .csproj
  • string = لا يمكن أن يكون null مطلقًا؛ string? = قد يكون null
  • يتتبع تحليل تدفق القيم حالة null عبر الفروع والقيم المُرجعة
  • تُستخدم تعليقات NRT في وقت الترجمة فقط — ولا تضيف أي تكلفة في وقت التشغيل
  • CS8618: هيّئ الحقول غير القابلة لـ null في المُنشئ أو استخدم = null! مع ORM
  • استخدم ! باعتدال — ووثّق سبب أمان عامل تجاهل null

الأسئلة الشائعة

هل درس «تمكين NRT وفهمه» مجاني؟

نعم — نص درس «تمكين NRT وفهمه» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.

ماذا ستتعلم في «تمكين NRT وفهمه»؟

فعّلوا سياق nullable، وافهموا أنواع المراجع nullable وغير nullable، واقرؤوا تحذيرات المترجم. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟

لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «تمكين NRT وفهمه»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟

نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تمكين NRT وفهمه
  2. التعليقات التوضيحية: ? و! وMaybeNull وNotNull
  3. العوامل Null-Conditional وNull-Coalescing
  4. ترحيل قاعدة شيفرة إلى NRT
← العودة إلى C# Academy