Внезапно задумался, а почему не работает вот такое:
foreach(var k in new int[10])
k = 42;
Ну, ладно, получаем
CS1656, Cannot assign to 'd' because it is a 'foreach iteration variable'.
Ладно, всё верно, у нас там под капотом
IEnumerable<int>, который возвращает
IEnumerator<int>, у которого
int Current{get;}. Действительно — куда там присваивать?
Но! У нас же есть возможность сделать ref int Current {get;}.
Жаль, но вот такой код компилироваться не будет:
public static IEnumerable<ref T> RefEnumerable(this T[] data)
{
for (var i = 0; i < data.Length; i++)
yield return ref data[i];
}
В первой же строке у нас Unexpected token 'ref'.
Ладно, папенька, пойдём длинным путём.
public interface IRefEnumerator<T>: IEnumerator, IDisposable
{
new ref T Current { get; }
}
public interface IRefEnumerable<T>
{
public IRefEnumerator<T> GetEnumerator();
}
public class ArrayEnumerable<T>: IRefEnumerable<T>
{
private T[] _data;
public ArrayEnumerable(T[] data ) => _data = data ?? throw new ArgumentNullException(nameof(data));
private class ArrayEnumerator<T>: IRefEnumerator<T>
{
private T[] _data;
private int _pos = -1;
public ArrayEnumerator(T[] data) => _data = data ?? throw new ArgumentNullException(nameof(data));
public ref T Current => ref _data[_pos];
object IEnumerator.Current => _data[_pos];
public void Dispose(){}
public bool MoveNext() => ++_pos < _data.Length;
public void Reset() => _pos = -1;
}
public IRefEnumerator<T> GetEnumerator() => new ArrayEnumerator<T>(_data);
}
public static class ArrayEnumerable
{
public static ArrayEnumerable<T> AsRefEnumerable<T>(this T[] data) => new ArrayEnumerable<T>(data);
}
Пока что всё компилируется.
Но вот почему
foreach(var k in (new int[10]).AsRefEnumerable())
k = 42;
по-прежнему выдаёт CS1656? И можно ли это доработать, незначительно поправив Roslyn?