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