Информация об изменениях

Сообщение Ref Enumerable от 29.04.2021 5:39

Изменено 29.04.2021 20:07 VladD2

Ref Enumerable
Внезапно задумался, а почему не работает вот такое:

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'.
Ладно, папенька, пойдём длинным путём.

[сs]
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);
}
[/cs]

Пока что всё компилируется.
Но вот почему
foreach(var k in (new int[10]).AsRefEnumerable())
  k = 42;

по-прежнему выдаёт CS1656? И можно ли это доработать, незначительно поправив Roslyn?
compiler
Ref Enumerable
Внезапно задумался, а почему не работает вот такое:

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?
compiler