C# Error CS4013 – Instance of type ‘{0}’ cannot be used inside a nested function, query expression, iterator block or async method

C# Error

CS4013 – Instance of type ‘{0}’ cannot be used inside a nested function, query expression, iterator block or async method

Reason for the Error & Solution

Instance of type cannot be used inside a nested function, query expression, iterator block or async method

Example

The following sample generates CS4013:

public class C
{
    public static IEnumerable<string> Lines(char[] text)
    {
        ReadOnlySpan<char> chars = text;
        var index = chars.IndexOf('\n');
        while (index > 0)
        {
            yield return chars[..index].ToString();
            chars = chars[(index + 1)..];
            index = chars.IndexOf('\n');
        }

        yield return chars.ToString();
    }
}

This enumerator method extracts lines of text from a character array. It naively tries to use ReadOnlySpan<T> to improve performance.

To correct this error

Lines(char[] text) is an enumerator function. An enumerator function compiles the method’s body into a state machine that manages the sequence of states the iterator function goes through while processing. That state machine is implemented as a generated class, and the state is implemented as variables within that class. That captured local state is forced from a stack context to a heap context. Since ref structs like ReadOnlySpan<T> cannot be stored in the heap, the CS4013 error is raised. To continue to use a ReadOnlySpan<T>, to correct this error, the method must be re-implemented as a non-iterator function, for example:

    public static IEnumerable<string> Lines2(char[] text)
    {
        ReadOnlySpan<char> chars = text;

        var lines = new List<string>();
        var index = chars.IndexOf('\n');
        while (index > 0)
        {
            lines.Add(chars[..index].ToString());
            chars = chars[(index+1)..];
            index = chars.IndexOf('\n');
        }

        lines.Add(chars.ToString());
        return lines;
    }

To continue to use an iterator function, to correct this error, the method must be re-implemented to avoid using ReadOnlySpan<T>, for example:

    public static IEnumerable<string> Lines2(char[] chars)
    {
        var startIndex = 0;
        var index = Array.IndexOf(chars,'\n');
        while (index > 0)
        {
            yield return new string(chars, startIndex, index);
            startIndex = index+1;
            index = Array.IndexOf(chars, '\n', startIndex);
        }
        yield return new string(chars, startIndex, chars.Length - startIndex);
    }