在C#中懒惰地转换IReadOnlyList

时间:2013-03-13 07:25:43

标签: c# list

我希望能够做这样的事情来设置一个 网格数据结构。

IReadOnlyList<Point> points;
IReadOnlyList<IReadOnlyList<int>> triangles;

其中三角形是点列表的索引。给出一个指数 一个三角形''''我们可以很容易地找到这些点

IEnumerable<Point> points = triangles[ti].Select(pi=>points[pi])

但是我希望能够定义一个方便结构

IReadOnlyList<IReadOnlyList<Point>> trianglesAsPoints;

所以我可以做到

IEnumerable<Point> points = triangles[ti]

这样做的显而易见的方法是创建类似linq的选择器

IReadOnlyList<T> Select( this IReadOnlyList<U> This
                             , Func<U,T> selector)

返回一个实例,其类重写以下方法和 调用选择器

public interface IReadOnlyList<out T> : IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    // Summary:
    //     Gets the element at the specified index in the read-only list.
    //
    // Parameters:
    //   index:
    //     The zero-based index of the element to get.
    //
    // Returns:
    //     The element at the specified index in the read-only list.
    T this[int index] { get; }
}

这样的工厂是否存在于标准库中的任何位置或nuget用于此模式? 注意我不希望IEnumerable因为我会失去索引能力 和Count属性,我只是想懒洋洋地转换值,这意味着 事先将所有值复制到新的列表实例。

2 个答案:

答案 0 :(得分:2)

我不相信在框架中有什么可以做到这一点,没有。这显然很容易实现,但我相信你必须这样做。完全可能有第三方库可以做到这一点,但由于IReadOnlyCollection仅在.NET 4.5中,它比接口存在一段时间的可能性小。

我建议将其称为Select之外的其他内容 - 我会使用ProjectView或类似内容。当然这意味着它不适用于LINQ查询表达式,但对于阅读代码的任何人来说,只有Enumerable.Select

才会更清楚。

答案 1 :(得分:1)

这是针对问题的手动解决方案

public static class CollectionMixins
{
    private class ReadOnlyListProjection<U,T> : IReadOnlyList<T>
    {

        public Func<U,T> Selector { get; private set; }
        public IList<U> List { get; private set; }

        public ReadOnlyListProjection(IList<U> list, Func<U, T> selector)
        {
            List = list;
            Selector = selector;
        }

        public T this[int index]
        {
            get { return Selector(List[index]);  }
        }

        public int Count
        {
            get { return List.Count; }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return List.Select(Selector).GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return List.Select(Selector).GetEnumerator();
        }
    }

    public static IReadOnlyList<T> ProjectReadOnly<U, T>(this IList<U> This, Func<U, T> fn)
    {
        return new ReadOnlyListProjection<U, T>(This, fn);
    }
}

所以我现在可以做到

IList<int> foo = new List<int>{0,1,2};
IReadOnlyList<string> bar = foo.ProjectReadOnly( x=>x.ToString() );