0Pricing
C# Academy · درس

دلالات التقييم الكسول

افهموا التنفيذ المؤجّل للتكرارات

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

التنفيذ المؤجل

تستخدم المكرّرات واستعلامات LINQ التنفيذ المؤجل: إذ لا يؤدي تعريف الاستعلام إلى أي عمل تقريبًا. ولا يبدأ العمل إلا عند تعداد النتيجة فعليًا، عنصرًا تلو الآخر.

لا يُنفَّذ شيء حتى تُعدِّد النتيجة

لا يؤدي استدعاء أسلوب مكرّر إلى تنفيذ جسمه. يبدأ الجسم في التنفيذ فقط عندما تسحب foreach (أو مستهلك آخر) القيمة الأولى.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Numbers()
    {
        Console.WriteLine("-- iterator body started --");
        yield return 1;
        yield return 2;
    }

    public static void Main()
    {
        var seq = Numbers();
        Console.WriteLine("query created, body not run yet");
        foreach (var n in seq) Console.WriteLine(n);
    }
}

تُنتَج القيم واحدة تلو الأخرى

ينفّذ كل تكرار من المكرّر القدر الكافي فقط لإنتاج القيمة التالية. ويحافظ هذا النموذج القائم على السحب على انخفاض استهلاك الذاكرة، حتى مع التسلسلات الضخمة.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Trace()
    {
        for (int i = 1; i <= 3; i++)
        {
            Console.WriteLine("producing " + i);
            yield return i;
        }
    }

    public static void Main()
    {
        foreach (var n in Trace())
            Console.WriteLine("consumed " + n);
    }
}

إعادة التعداد تعيد التنفيذ

لا تحتوي السلسلة المؤجلة على نتيجة مخزّنة مؤقتًا. ويؤدي تعدادها مرتين إلى تنفيذ المكرّر مرتين، وهو أمر مهم إذا تغيّر المصدر أو كانت العملية مكلفة.

using System;
using System.Collections.Generic;

public class Program
{
    static int _calls = 0;
    static IEnumerable<int> Counter()
    {
        _calls++;
        yield return _calls;
    }

    public static void Main()
    {
        var seq = Counter();
        foreach (var n in seq) Console.WriteLine(n);
        foreach (var n in seq) Console.WriteLine(n);
        Console.WriteLine("total runs: " + _calls);
    }
}

قراءة الحالة الحالية

بما أن التنفيذ مؤجل، يقرأ المكرّر مصدره وقت التعداد، لا وقت التعريف. لذلك تظهر التغييرات التي تُجرى بعد تعريف الاستعلام.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var list = new List<int> { 1, 2 };
        IEnumerable<int> doubled = Double(list);
        list.Add(3); // added before enumeration
        foreach (var n in doubled) Console.WriteLine(n);
    }

    static IEnumerable<int> Double(IEnumerable<int> nums)
    {
        foreach (var n in nums) yield return n * 2;
    }
}

فرض التنفيذ الفوري

لأخذ لقطة من النتائج، ثبّت التسلسل باستخدام ToList() أو ToArray(). يؤدي ذلك إلى تشغيل المكرّر مرة واحدة وتخزين القيم، وفصلها عن التغييرات اللاحقة في المصدر.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var list = new List<int> { 1, 2 };
        List<int> snapshot = Double(list).ToList(); // executed now
        list.Add(99);
        Console.WriteLine(string.Join(",", snapshot));
    }

    static IEnumerable<int> Double(IEnumerable<int> nums)
    {
        foreach (var n in nums) yield return n * 2;
    }
}

التوقّف المبكر يوفر الجهد

بما أن المستهلكين يسحبون القيم عند الحاجة، يمكن لعملية مثل البحث عن أول تطابق أن تتوقف مبكرًا. ولا يُجري المنتج حساب القيم التي لم تُطلب قط.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    static IEnumerable<int> Numbers()
    {
        for (int i = 1; ; i++)
        {
            Console.WriteLine("checking " + i);
            yield return i;
        }
    }

    public static void Main()
    {
        int firstBig = Numbers().First(n => n > 3);
        Console.WriteLine("found " + firstBig);
    }
}

الاستثناءات المؤجلة

لا يُرمى الاستثناء الموجود داخل المكرّر عند استدعاء الأسلوب، بل عندما يصل التعداد إلى السطر المتسبب في الخطأ. وقد يفاجئك ذلك إذا كنت تتوقع إجراء التحقق مسبقًا.

using System;
using System.Collections.Generic;

public class Program
{
    static IEnumerable<int> Risky(int divisor)
    {
        yield return 10 / divisor; // throws only during enumeration
    }

    public static void Main()
    {
        var seq = Risky(0);
        Console.WriteLine("no error yet");
        try { foreach (var n in seq) Console.WriteLine(n); }
        catch (DivideByZeroException) { Console.WriteLine("caught during enumeration"); }
    }
}

تركيب خطوط المعالجة الكسولة بكلفة منخفضة

لا يؤدي تسلسل المعاملات الكسولة إلى تنفيذها مرارًا. يمر كل عنصر عبر خط المعالجة بأكمله مرة واحدة، عند الطلب، مما يحقق كفاءة عالية واستهلاكًا منخفضًا للذاكرة.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var result = Enumerable.Range(1, 1000000)
            .Where(n => n % 2 == 0)
            .Select(n => n * n)
            .Take(3);
        foreach (var n in result) Console.WriteLine(n);
    }
}

متى تثبّت النتائج

ثبّت النتائج عندما تريد تعدادها عدة مرات، أو عندما يكون المصدر عرضة للتغيير، أو عندما يجب التقاط النتائج قبل التخلص من مورد ما. وفي غير ذلك، أبقِ التنفيذ كسولًا لتوفير الذاكرة والجهد.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var evens = Enumerable.Range(1, 10).Where(n => n % 2 == 0).ToList();
        // Safe to enumerate many times now
        Console.WriteLine("count: " + evens.Count);
        Console.WriteLine("sum: " + evens.Sum());
    }
}

جرّب بنفسك

راقب التنفيذ المؤجل مباشرةً: عرّف استعلامًا، ثم غيّر المصدر، ولاحظ التغييرات في النتائج عند التعداد فقط.

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var source = new List<int> { 1, 2, 3 };
        var query = source.Where(n => n > 1); // not executed yet
        source.Add(10);
        source.Remove(2);
        // Executes now, reflecting all changes
        Console.WriteLine(string.Join(", ", query));
    }
}

تحقق سريع

حلّل طريقة عمل التنفيذ المؤجل.

مراجعة

لا يُقيَّم التسلسل تقييمًا كسولًا (مؤجلًا) إلا عند تعداده.

  • لا ينفّذ تعريف الاستعلام أي عمل؛ أما استهلاكه فينفّذ العمل.
  • تؤدي إعادة التعداد إلى إعادة تشغيل المكرّر.
  • تُقرأ المصادر وقت التعداد، لذلك تظهر التغييرات اللاحقة.
  • تظهر الاستثناءات أثناء التعداد.
  • استخدم ToList()/ToArray() لتثبيت النتائج عند الحاجة.

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

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

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

ماذا ستتعلم في «دلالات التقييم الكسول»؟

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

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

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

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

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

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

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

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

  1. أساليب التكرار باستخدام yield return
  2. ‏yield break والإنهاء المبكر
  3. دلالات التقييم الكسول
  4. الأنواع القابلة للتعداد المخصّصة
← العودة إلى C# Academy