はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】unsafeを用いずにReadOnlySpan<char>からSpan<char>に変換をして中身を好き勝手にいじる

はじめに

今回はunsafeを用いずにReadOnlySpan<Span>からSpan<char>に変換する方法について紹介をしたいと思います。

ReadOnlySpan<char> str = "hello, world";
var span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(str), str.Length);
        
// unsafe使わずともこれで簡単にいじれてしまうやん...
span.Reverse();
        
// dlrow ,olleh
Console.WriteLine(str.ToString());
Console.WriteLine(span.ToString());

概要

Spanに変更するためにはMemoryMarshal.CreateSpanMemoryMarshal.GetReferenceを組み合わせます。

MemoryMarshal.CreateSpan

public static Span<T> CreateSpan<T> (scoped ref T reference, int length);

定期的なマネージド オブジェクトの一部に対する新しいスパンを作成します。

learn.microsoft.com

referenceに先頭のアドレスを渡し、あとはlengthで要素数を渡してあげればSpanを生成できます。

MemoryMarshal.GetReference

public static ref T GetReference<T> (ReadOnlySpan<T> span);
public static ref T GetReference<T> (Span<T> span);

インデックス 0 にある(読み取り専用)スパンの要素の参照を返します。

learn.microsoft.com

先頭のアドレスを取得します。ReadOnlySpanの方のオーバーロードを今回は利用していきます。

やり方

ReadOnlySpan<char> str = "hello, world";
var span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(str), str.Length);
        
// unsafe使わずともこれで簡単にいじれてしまうやん...
span.Reverse();
span[0] = 'A';
        
// Alrow ,olleh
Console.WriteLine(str.ToString());
Console.WriteLine(span.ToString());

Spanに対して操作をすれば、同じメモリ領域を指しているので中身を好き勝手いじれるというわけですね。

もはやReadOnlyは中身を書き換えないでねという意思表示になっているといってもいいかもしれません。