C# Academy · レッスン

Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ

配列の代わりにArraySegment を渡します。ウィンドウを作り、Skip/Take/Sliceを実装し、ヘッダーとペイロードを解析し、境界でのみコピーします。

レッスン 2/38 ステップ

「Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン2/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全3レッスンが含まれています。

配列上のウィンドウ

目的: 配列をメモリ上のウィンドウとして扱います。

  • ビューを渡すためにArraySegment<T>を使います
  • 小さなSkip/Take/Sliceヘルパーを構築します
  • コピーせずにヘッダーとペイロードを解析します
  • I/Oの境界でのみコピーします

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));
  }
}

規約による読み取り専用

ArraySegmentを使うC# 6では、読み取り専用の動作は規約です。読み取りだけを保証する関数の内部では、決して変更しないでください。

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));
  }
}

ウィンドウが役立つ理由

確認問題: パーサーにbyte[]ではなくArraySegmentを渡すのはなぜですか?

振り返り

振り返り: ArraySegment<T>をMemoryのようなウィンドウとして使います。Skip/Take/Sliceで組み合わせ、offsetで解析し、必要な場合にのみコピーします。

無料で開始

AI チューターと学ぶ C# — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
93
レッスン
346

よくある質問

「Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ」レッスンは無料ですか?

はい。「Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全3レッスンが含まれています。

「Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ」で何を学びますか?

配列の代わりにArraySegment を渡します。ウィンドウを作り、Skip/Take/Sliceを実装し、ヘッダーとペイロードを解析し、境界でのみコピーします。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/3です。

「Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Span/ReadOnlySpanの基礎(C# 6でのエミュレーション)
  2. Memory/ReadOnlyMemoryのエミュレーション:ゼロコピーのウィンドウ
  3. 文字列をSpanとして扱うAPI(C# 6でのエミュレーション)
← C# Academyに戻る