Эмуляция 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]);
}
}
Копирование между окнами
Используйте 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
}
}
Разбор заголовка и полезных данных
Выполняйте разбор по смещению и создавайте окно полезных данных. Преобразуйте данные в текст только при необходимости.
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<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 включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы Span/ReadOnlySpan (эмуляция в C# 6)
- Эмуляция Memory/ReadOnlyMemory: окна без копирования
- API «строка как Span» (эмуляция в C# 6)