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>
!