I have gotten some weird result when playing around with Spans in C# and I’m not sure what I’m doing wrong. In order to boil the problem down I made a simple test case:
public static void DecSpans(Span<byte> b1, Span<byte> b2)
{
for (int i = 0; i < b1.Length; ++i)
{
b1[i] = (byte)(b1[i] - b2[i]);
}
}
[DataTestMethod]
public void TestSpan()
{
byte[] buf1 = new byte[4] { 1, 2, 3, 4 };
DecSpans(buf1[..], buf1);
Assert.IsTrue(buf1.All(b => b == 0));
}
buf1 is not modified for some reason when I make it a slice. If I remove the [..] then buf1 is modified. Am I doing something illegal here?
>Solution :
Nothing to do with spans.
When you use the slice operator on a type, you get back an instance of the same type. So when you use a slice on an array, you get back a new array.
Therefore buf1[..] is the same as buf1.ToArray(): it allocates a new array and copies buf1 into it. You then re-assign elements in this temporary array, and discard it.
To create a span which points to an array, use buf1.AsSpan().
I think you’re used to Rust, where a slice produces its own dedicated type. That’s not how C# works. For instance, it’s not safe to create a Span<T> which points to the underlying storage of a List<T> (as that storage can be reallocated as the list grows). If a slice always produces a Span<T>, then slicing a list would either by forbidden, or unsafe, neither of which is desirable (and C# has no borrow checker to forbid this). Following the rule that a slice returns an instance of the same type alleviates this.