如何将ICollection <t>转换为IReadOnlyCollection <t>?

时间:2015-12-18 19:04:00

标签: c# icollection

当我在C#中有ICollection<T>变量时,我无法将其传递给期望IReadOnlyCollection<T>的函数:

public void Foo()
{
  ICollection<int> data = new List<int>();
  // Bar(data); // Not allowed: Cannot implicitly cast ICollection<int> to IReadOnlyCollection<int>
  Bar(data.ToList()); // Works, since List<T> implements IReadOnlyCollection<T>
}

public void Bar(IReadOnlyCollection<int> data)
{
  if (data.Count == 1) { /* ... */ }
  // ...
}

显然问题是ICollection<T>不会继承IReadOnlyCollection<T> - 但为什么? ICollection<T>应该是IReadOnlyCollection<T>的完整功能集以及修改集合的函数。

传递参数的最佳解决方案是什么?

一方面,由于我不想改变Bar中的集合,只需要计数并迭代集合,我想要IReadOnlyCollection

另一方面,每次调用该函数时,我都不想创建新的列表对象。

2 个答案:

答案 0 :(得分:6)

没有标准的解决方案AFAIK,但是这样做并不困难

public static class MyExtensions
{
    public static IReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> source)
    {
        if (source == null) throw new ArgumentNullException("source");
        return source as IReadOnlyCollection<T> ?? new ReadOnlyCollectionAdapter<T>(source);
    }

    sealed class ReadOnlyCollectionAdapter<T> : IReadOnlyCollection<T>
    {
        readonly ICollection<T> source;
        public ReadOnlyCollectionAdapter(ICollection<T> source) => this.source = source;
        public int Count => source.Count;
        public IEnumerator<T> GetEnumerator() => source.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }
}

然后按如下方式使用

Bar(data.AsReadOnly());

答案 1 :(得分:5)

在实施ICollection<T>时,您可以非常简单地创建一个组成IReadOnlyCollection<T>的类。您还可以创建一个扩展方法来进行包装(从而允许通用类型推断):

public class ReadOnlyCollectionWrapper<T> : IReadOnlyCollection<T>
{
    private ICollection<T> collection;
    public ReadOnlyCollectionWrapper(ICollection<T> collection)
    {
        this.collection = collection;
    }

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

    public IEnumerator<T> GetEnumerator()
    {
        return collection.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return collection.GetEnumerator();
    }
}

public static class ReadOnlyCollectionWrapper
{
    public static IReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> collection)
    {
        return new ReadOnlyCollectionWrapper<T>(collection);
    }
}