0Pricing
C# Academy · درس

التعليقات التوضيحية: ? و! وMaybeNull وNotNull

استخدموا ? للأنواع nullable، و! لإعفاء null، وسمات مثل MaybeNull وNotNullWhen لتحليل التدفق بدقة.

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

ما بعد ? و!: سمات قابلية null

تعالج تعليمة ? الأساسية والتحقق من null معظم الحالات، لكن بعض الأنماط تحتاج إلى تعليقات أكثر تعبيرًا. توفر مساحة الأسماء System.Diagnostics.CodeAnalysis سمات تمنح المترجم رؤية أعمق لتدفق null.

MaybeNull وNotNull

تخبر [MaybeNull] المترجم بأن نوعًا مُرجعًا غير قابل لـ null قد يكون null فعليًا (مثل أسلوب عام). وتضمن [NotNull] أن معلمة قابلة لـ null لن تكون null بعد استدعاء الأسلوب.

using System.Diagnostics.CodeAnalysis;

// [MaybeNull]: return might be null even though T is non-nullable
[return: MaybeNull]
public T Find<T>(int id)
{
    // Returns default(T) which is null for reference types
    return _cache.TryGetValue(id, out var val) ? val : default!;
}

// [NotNull]: after this call, output is guaranteed non-null
public static void EnsureNotNull<T>(
    [NotNull] ref T? value,
    T defaultValue) where T : class
{
    value ??= defaultValue;
}

NotNullWhen: عدم قابلية null المشروطة

تخبر [NotNullWhen(true)] المترجم بأن معلمة إخراج ستكون غير مساوية لـ null عندما يُرجع الأسلوب true. هكذا يُعلَّق نمط TryParse القياسي.

using System.Diagnostics.CodeAnalysis;

public static bool TryParseEmail(
    string? input,
    [NotNullWhen(true)] out string? email)
{
    if (input?.Contains('@') == true)
    {
        email = input.Trim().ToLower();
        return true;
    }
    email = null;
    return false;
}

// Usage — no warning after true check:
if (TryParseEmail(raw, out var email))
    Console.WriteLine(email.Length); // safe — email is non-null here

MaybeNullWhen: قابلية null المشروطة

تُعد [MaybeNullWhen(false)] عكس ذلك — فقد تكون قيمة الإخراج null عندما يُرجع الأسلوب false. وتُستخدم في أنماط القاموس TryGetValue.

// This is how Dictionary<K,V>.TryGetValue is annotated:
public bool TryGetValue(
    TKey key,
    [MaybeNullWhen(false)] out TValue value)
{ ... }

// Usage:
if (!dict.TryGetValue("key", out var value))
    return; // early return — value is null in this branch

Console.WriteLine(value.Length); // safe after the guard

AllowNull وDisallowNull

تسمح [AllowNull] الموضوعة على خاصية غير قابلة لـ null للمتصلين بتمرير null إليها (مثل أداة setter تحوّل null إلى سلسلة فارغة). وتحظر [DisallowNull] استخدام null مع نوع قابل لـ null.

public class Config
{
    private string _name = "";

    // Allow setting null (setter converts null -> empty)
    [AllowNull]
    public string Name
    {
        get => _name;
        set => _name = value ?? "";
    }

    // Getter always returns non-null: fine
    // Setter accepts null: [AllowNull] tells compiler that's OK
}

NotNullIfNotNull: نشر قابلية null

تعني [NotNullIfNotNull(paramName)] ما يلي: إذا كانت المعلمة X غير مساوية لـ null، فستكون القيمة المُرجعة غير مساوية لـ null أيضًا. وهذا مفيد في دوال التحويل.

[return: NotNullIfNotNull(nameof(value))]
public static string? Normalize(string? value)
{
    return value?.Trim().ToLower();
}

// Usage:
string  name = "  Alice  ";
string  norm1 = Normalize(name)!; // guaranteed non-null
string? raw   = GetRaw();
string? norm2 = Normalize(raw);   // still nullable (raw might be null)

DoesNotReturn

تحدد [DoesNotReturn] أسلوبًا يُلقي استثناءً دائمًا. ويعرف المترجم أن التعليمة البرمجية بعد الاستدعاء غير قابلة للوصول، فيمنع تحذيرات null غير الضرورية.

using System.Diagnostics.CodeAnalysis;

[DoesNotReturn]
public static void ThrowNotFound(int id)
    => throw new KeyNotFoundException($"Entity {id} not found");

// Usage — no null warning after the call:
var order = _db.Orders.Find(id);
if (order is null) ThrowNotFound(id);

Console.WriteLine(order.Id); // no CS8602 — compiler knows ThrowNotFound threw

MemberNotNull: شرط لاحق للحقول

تخبر [MemberNotNull] المترجم بأن أسلوبًا ما يضمن أن حقولًا معينة غير مساوية لـ null بعد عودته. وهذا مفيد في أدوات المساعدة للتهيئة الكسولة.

public class DataLoader
{
    private string? _data;

    [MemberNotNull(nameof(_data))]
    private void EnsureLoaded()
    {
        if (_data is null)
            _data = LoadFromFile();
    }

    public string GetData()
    {
        EnsureLoaded();
        return _data; // no CS8603 — compiler knows _data is set
    }
}

دمج السمات

يمكن دمج السمات لإنشاء عقود دقيقة لواجهات API. إليك أداة مساعدة للحراسة بأسلوب fluent تجمع عدة سمات.

public static class Guard
{
    [return: NotNull]
    public static T NotNull<T>(
        [NotNull][AllowNull] T? value,
        [CallerArgumentExpression(nameof(value))] string? name = null)
        where T : class
    {
        ArgumentNullException.ThrowIfNull(value, name);
        return value;
    }
}

// Usage:
var product = Guard.NotNull(await _repo.FindAsync(id));
Console.WriteLine(product.Name); // no warning

عوامل null: ?. و?? و??=

تتيح عوامل الشرط المتعلق بـ null (?.)، والدمج مع null (??)، والإسناد بالدمج مع null (??=) كتابة تعليمات برمجية موجزة وآمنة تجاه null دون عمليات تحقق مطولة باستخدام if.

string? name = GetName();

// ?. safe navigation
int? len = name?.Length;
string? upper = name?.ToUpper().Trim();

// ?? default value
string display = name ?? "Anonymous";

// ??= lazy init
name ??= "Default";

// Chaining
string result = user?.Profile?.DisplayName ?? user?.Name ?? "Guest";

تحقق سريع

ماذا تخبر [NotNullWhen(true)] الموضوعة على معلمة out المترجمَ به؟

مراجعة: تعليقات قابلية null

أهم النقاط:

  • [NotNullWhen(true)]: نمط TryParse — قيمة غير مساوية لـ null عند الإرجاع true
  • [MaybeNull]: قد يُرجع النوع غير القابل لـ null قيمة null رغم ذلك (القيم الافتراضية للأنواع العامة)
  • [DoesNotReturn]: الأسلوب يُلقي استثناءً دائمًا — والتعليمات البرمجية بعده غير قابلة للوصول
  • [MemberNotNull]: يضمن الأسلوب تعيين الحقول بعد عودته
  • ?. و?? و??=: تنقل آمنة تجاه null وقيم افتراضية بطريقة موجزة

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

هل درس «التعليقات التوضيحية: ? و! وMaybeNull وNotNull» مجاني؟

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

ماذا ستتعلم في «التعليقات التوضيحية: ? و! وMaybeNull وNotNull»؟

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

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

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

كم من الوقت يستغرق درس «التعليقات التوضيحية: ? و! وMaybeNull وNotNull»؟

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

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

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

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

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