Using Span<T> Instead Of List<T>

Imagine the code that converts Linux symbolic permissions to their octal representation. However, for some weird reason instead of accepting string with permissions, it accepts List<char>.

public static int SymbolicToOctal(List<char> input)
{
    var permission = SymbolicPermission.Parse(input);
    return permission.GetOctalRepresentation();
}

SymbolicPermission class, in turn, accepts ReadOnlySpan<char>, validates it, and calls private constructor

public static SymbolicPermission Parse(ReadOnlySpan<char> input)
{
	if (input.Length != BlockCount * BlockLength)
	{
		throw new ArgumentException("input should be a string 3 blocks of 3 characters each");
	}
	for (var i = 0; i < input.Length; i++)
	{
		TestCharForValidity(input, i);
	}

	return new SymbolicPermission(input);
}

This way we construct always valid domain objects.

Since string is an array of char and we have no problem with converting string to ReadOnlySpan<char> we might expect similar behavior from List<char>. After all, they both are just indexed collections that utilize array under the hood.

But in fact, things are not so rosy,

The way to combat this is to use CollectionsMarshal.AsSpan helper method,

public static int SymbolicToOctal(List<char> input)
{
    var permission = SymbolicPermission.Parse(CollectionsMarshal.AsSpan(input));
    return permission.GetOctalRepresentation();
}

Now everything compiles and you are able to leverage performance benefits of Span<T>!


Similar Articles