Emulacja Memory/ReadOnlyMemory: okna bez kopiowania
Proszę przekazywać ArraySegment zamiast tablic: tworzyć okna, implementować Skip/Take/Slice, analizować nagłówki i dane oraz kopiować tylko na granicach.
Emulacja Memory/ReadOnlyMemory: okna bez kopiowania to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 3 lekcji w sumie.
Okna nad tablicami
Cel: Traktować tablice jak okna pamięci.
- Używać ArraySegment<T> do przekazywania widoków
- Tworzyć małe pomocniki Skip/Take/Slice
- Analizować nagłówki i payloady bez kopiowania
- Kopiować wyłącznie na granicach I/O
Pomocniki Skip/Take/Slice
Należy utworzyć małe pomocniki Slice, Skip i Take, aby w przejrzysty sposób składać okna.
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]);
}
}
Kopiowanie między oknami
Należy używać Buffer.BlockCopy do przenoszenia danych między oknami bez tworzenia nowych tablic.
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
}
}
Analizowanie nagłówka i payloadu
Należy analizować dane według offset i utworzyć okno payloadu. Do tekstu należy konwertować dane tylko wtedy, gdy jest to potrzebne.
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));
}
}
Tylko do odczytu przez konwencję
Zachowanie tylko do odczytu jest w C# 6 konwencją przy użyciu ArraySegment: nie należy modyfikować danych wewnątrz funkcji, które obiecują wyłącznie odczyt.
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);
}
}
Kopiowanie na granicach
Należy kopiować wyłącznie na granicy (przy przekazywaniu do innej warstwy, logowaniu lub zapisywaniu). Wewnętrzne kroki powinny pozostać bez kopiowania.
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));
}
}
Szybkie sprawdzenie: Dlaczego parserowi należy przekazywać ArraySegment<byte> zamiast byte[]?
Podsumowanie
Podsumowanie: Należy używać ArraySegment<T> jako okna podobnego do Memory. Okna należy składać za pomocą Skip/Take/Slice, analizować dane według offsetów i kopiować tylko wtedy, gdy jest to konieczne.
Często zadawane pytania
Czy lekcja „Emulacja Memory/ReadOnlyMemory: okna bez kopiowania” jest bezpłatna?
Tak — pełny tekst „Emulacja Memory/ReadOnlyMemory: okna bez kopiowania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 3 lekcji w sumie.
Co nauczysz się w „Emulacja Memory/ReadOnlyMemory: okna bez kopiowania”?
Proszę przekazywać ArraySegment zamiast tablic: tworzyć okna, implementować Skip/Take/Slice, analizować nagłówki i dane oraz kopiować tylko na granicach. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C# Academy?
Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.
Ile czasu zajmuje lekcja „Emulacja Memory/ReadOnlyMemory: okna bez kopiowania”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?
Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Podstawy Span/ReadOnlySpan (emulacja w C# 6)
- Emulacja Memory/ReadOnlyMemory: okna bez kopiowania
- API string jako Span (emulacja w C# 6)