Создать IObservableList из списка IObservable - PullRequest
1 голос
/ 04 апреля 2019

Я ищу реактивный объект, который реализует IObservable<IReadOnlyList<T>> и IList<IObservable<T>>.

Вот и все, я хотел бы иметь возможность написать:

var list = new MyReactiveList<int>();
var item = new new Subject<int>();
list.Subscribe(values => Console.WriteLine($"[{string.Join(", ", values)}]"));
list.Add(item);
item.OnNext(1); // Will print out [1]

1 Ответ

2 голосов
/ 05 апреля 2019

Прежде всего, ваш код, который вы разместили в своем вопросе, не компилируется. Я исправил это как могу:

var list = new MyReactiveList<int>();
var item = new Subject<int>();
list.Subscribe(values => Console.WriteLine($"[{string.Join(", ", values)}]"));
list.Add(item);
item.OnNext(1); // Will print out [1]

Теперь упражнение состоит в том, чтобы просто реализовать class MyReactiveList<T> : IObservable<IReadOnlyList<T>>, IList<IObservable<T>>. Это довольно просто, но единственная проблема состоит в том, чтобы каким-то образом преобразовать изменяемый List<IObservable<T>> в IObservable<IReadOnlyList<T>> так, чтобы наблюдаемое обновлялось само при изменении списка.

Вот оно:

public class MyReactiveList<T> : IObservable<IReadOnlyList<T>>, IList<IObservable<T>>
{
    private List<IObservable<T>> _list = new List<IObservable<T>>();

    private Subject<Unit> _update = new Subject<Unit>();

    public IDisposable Subscribe(IObserver<IReadOnlyList<T>> observer) =>
        _update
            .Select(_ => _list.CombineLatest().Select(x => new ReadOnlyList<T>(x)))
            .Switch()
            .Subscribe(observer);

    public IObservable<T> this[int index]
    {
        get => _list[index];
        set
        {
            _list[index] = value;
            _update.OnNext(Unit.Default);
        }
    }

    public int Count => _list.Count;

    public bool IsReadOnly => false;

    public void Add(IObservable<T> item)
    {
        _list.Add(item);
        _update.OnNext(Unit.Default);
    }

    public void Clear()
    {
        _list.Clear();
        _update.OnNext(Unit.Default);
    }

    public bool Contains(IObservable<T> item) => _list.Contains(item);

    public void CopyTo(IObservable<T>[] array, int arrayIndex)
    {
        _list.CopyTo(array, arrayIndex);
    }

    public IEnumerator<IObservable<T>> GetEnumerator() => _list.GetEnumerator();

    public int IndexOf(IObservable<T> item) => _list.IndexOf(item);

    public void Insert(int index, IObservable<T> item)
    {
        _list.Insert(index, item);
        _update.OnNext(Unit.Default);
    }

    public bool Remove(IObservable<T> item)
    {
        var removed = _list.Remove(item);
        _update.OnNext(Unit.Default);
        return removed;
    }

    public void RemoveAt(int index)
    {
        _list.RemoveAt(index);
        _update.OnNext(Unit.Default);
    }

    IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
}

public class ReadOnlyList<T> : IReadOnlyList<T>
{
    public ReadOnlyList(IEnumerable<T> items) { _list.AddRange(items); }

    private List<T> _list = new List<T>();

    public T this[int index] => _list[index];

    public int Count => _list.Count;

    public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
}

NB. Реализовывать свои собственные наблюдаемые не очень хорошая идея - их легко ошибиться и создать код, который плохо сочетается с параллелизмом.

...