0Pricing
C# Academy · درس

محاكاة Memory/ReadOnlyMemory: نوافذ دون نسخ

مرّر ArraySegment بدلًا من المصفوفات: أنشئ نوافذ، ونفّذ Skip/Take/Slice، وحلّل الرؤوس والحمولات، ولا تنسخ إلا عند الحدود.

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

نوافذ فوق المصفوفات

الهدف: تعامل مع المصفوفات بوصفها نوافذ ذاكرة.

  • استخدم ArraySegment<T> لتمرير العروض
  • أنشئ مساعدات صغيرة باسم Skip/Take/Slice
  • حلّل الترويسات والحمولات من دون نسخ
  • انسخ فقط عند حدود الإدخال والإخراج

مساعدات Skip/Take/Slice

أنشئ مساعدات صغيرة باسم Slice وSkip وTake لتركيب النوافذ بوضوح.

using System;

public static class Seg
{
  public static ArraySegment<T> Slice<T>(ArraySegment<T> s, int start, int count)
  {
    if (start < 0 || count < 0 || start + count > s.Count) throw new ArgumentOutOfRangeException();
    return new ArraySegment<T>(s.Array, s.Offset + start, count);
  }

  public static ArraySegment<T> Skip<T>(ArraySegment<T> s, int n)
  {
    if (n < 0 || n > s.Count) throw new ArgumentOutOfRangeException("n");
    return new ArraySegment<T>(s.Array, s.Offset + n, s.Count - n);
  }

  public static ArraySegment<T> Take<T>(ArraySegment<T> s, int n)
  {
    if (n < 0 || n > s.Count) throw new ArgumentOutOfRangeException("n");
    return new ArraySegment<T>(s.Array, s.Offset, n);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    int[] xs = new int[] { 10, 20, 30, 40, 50 };
    ArraySegment<int> view = new ArraySegment<int>(xs, 1, 3); // 20,30,40
    ArraySegment<int> head = Seg.Take<int>(view, 2);          // 20,30
    ArraySegment<int> tail = Seg.Skip<int>(view, 1);          // 30,40
    Console.WriteLine(head.Array[head.Offset] + "," + head.Array[head.Offset + 1]);
    Console.WriteLine(tail.Array[tail.Offset] + "," + tail.Array[tail.Offset + 1]);
  }
}

نسخ من نافذة إلى نافذة

استخدم Buffer.BlockCopy لنقل البيانات بين النوافذ من دون إنشاء مصفوفات جديدة.

using System;

public static class SegCopy
{
  public static int Copy(ArraySegment<byte> src, ArraySegment<byte> dst)
  {
    int n = src.Count < dst.Count ? src.Count : dst.Count;
    Buffer.BlockCopy(src.Array, src.Offset, dst.Array, dst.Offset, n);
    return n;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    byte[] a = new byte[] { 1, 2, 3, 4, 5, 6 };
    byte[] b = new byte[] { 0, 0, 0, 0, 0, 0 };

    ArraySegment<byte> winA = new ArraySegment<byte>(a, 2, 3); // 3,4,5
    ArraySegment<byte> winB = new ArraySegment<byte>(b, 1, 3); // target

    int copied = SegCopy.Copy(winA, winB);
    Console.WriteLine("Copied: " + copied);
    Console.WriteLine(string.Join(",", b)); // 0,3,4,5,0,0
  }
}

تحليل الترويسة والحمولة

حلّل باستخدام offset وأنشئ نافذة للحمولة. حوّل إلى نص عند الحاجة فقط.

using System;
using System.Text;

public static class Parser
{
  // Message layout: [len:2 bytes little-endian][type:1 byte][payload:len bytes]
  public static void Parse(ArraySegment<byte> msg)
  {
    if (msg.Count < 3) throw new ArgumentException("message too short");

    int o = msg.Offset;
    byte[] arr = msg.Array;

    int len = arr[o] | (arr[o + 1] << 8); // ushort little-endian
    byte typ = arr[o + 2];

    ArraySegment<byte> payload = new ArraySegment<byte>(arr, o + 3, len);
    Console.WriteLine("Type=" + typ + " Len=" + len);

    // Materialize only at the boundary (to string for display)
    string text = Encoding.ASCII.GetString(payload.Array, payload.Offset, payload.Count);
    Console.WriteLine("Payload: " + text);
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    // Build: len=5 ("Hello"), type=42
    byte[] buf = new byte[3 + 5];
    buf[0] = 5; buf[1] = 0; buf[2] = 42;
    byte[] hello = Encoding.ASCII.GetBytes("Hello");
    Buffer.BlockCopy(hello, 0, buf, 3, 5);

    Parser.Parse(new ArraySegment<byte>(buf, 0, buf.Length));
  }
}

للقراءة فقط بالاصطلاح

يُحدَّد سلوك القراءة فقط باصطلاح في C# 6 مع ArraySegment: لا تعدّل أبدًا داخل الدوال التي تتعهد بالقراءة فقط.

using System;

public static class Checksums
{
  // Treat the segment as "read-only": never write to seg.Array here.
  public static int SumBytes(ArraySegment<byte> seg)
  {
    int end = seg.Offset + seg.Count;
    int total = 0;
    for (int i = seg.Offset; i < end; i++) total += seg.Array[i];
    return total & 0xFF;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    byte[] data = new byte[] { 10, 20, 30, 40, 50 };
    ArraySegment<byte> window = new ArraySegment<byte>(data, 1, 3); // 20,30,40
    int checksum = Checksums.SumBytes(window);
    Console.WriteLine("Checksum = " + checksum);
  }
}

النسخ عند الحدود

انسخ فقط عند الحافة (عند الإرسال إلى طبقة أخرى أو التسجيل أو التخزين). وأبقِ الخطوات الداخلية بلا نسخ.

using System;

public static class Materialize
{
  public static T[] ToArray<T>(ArraySegment<T> s)
  {
    T[] copy = new T[s.Count];
    Array.Copy(s.Array, s.Offset, copy, 0, s.Count);
    return copy;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    int[] data = new int[] { 5, 6, 7, 8, 9 };
    ArraySegment<int> middle = new ArraySegment<int>(data, 1, 3); // 6,7,8
    int[] copy = Materialize.ToArray<int>(middle); // copy at boundary
    Console.WriteLine(string.Join(",", copy));
  }
}

فائدة النوافذ

تحقّق سريع: لماذا تمرّر ArraySegment إلى محلّل بدلًا من byte[]؟

مراجعة

مراجعة: استخدم ArraySegment<T> كنافذة شبيهة بالذاكرة. ركّبها باستخدام Skip/Take/Slice، وحلّل عبر الإزاحات، وانسخ فقط عند الضرورة.

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

هل درس «محاكاة Memory/ReadOnlyMemory: نوافذ دون نسخ» مجاني؟

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

ماذا ستتعلم في «محاكاة Memory/ReadOnlyMemory: نوافذ دون نسخ»؟

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

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

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

كم من الوقت يستغرق درس «محاكاة Memory/ReadOnlyMemory: نوافذ دون نسخ»؟

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

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

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

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

  1. أساسيات Span/ReadOnlySpan (محاكاة C# 6)
  2. محاكاة Memory/ReadOnlyMemory: نوافذ دون نسخ
  3. واجهات String-as-Span (محاكاة C# 6)
← العودة إلى C# Academy