当我ICollection
在C#中有一个变量时,我无法将它传递给期望IReadOnlyCollection
:
public void Foo() { ICollectiondata = new List (); // Bar(data); // Not allowed: Cannot implicitly cast ICollection to IReadOnlyCollection Bar(data.ToList()); // Works, since List implements IReadOnlyCollection } public void Bar(IReadOnlyCollection data) { if (data.Count == 1) { /* ... */ } // ... }
显然问题是ICollection
不继承IReadOnlyCollection
- 但为什么?ICollection
应该是完整的功能集IReadOnlyCollection
以及修改集合的函数.
传递参数的最佳解决方案是什么?
一方面,因为我不想改变集合Bar
,只需要计数并迭代集合,我想要一个IReadOnlyCollection
.
另一方面,每次调用该函数时,我都不想创建新的列表对象.
没有标准的解决方案AFAIK,但是像这样制作自己的并不难
public static class MyExtensions { public static IReadOnlyCollectionAsReadOnly (this ICollection source) { if (source == null) throw new ArgumentNullException("source"); return source as IReadOnlyCollection ?? new ReadOnlyCollectionAdapter (source); } sealed class ReadOnlyCollectionAdapter : IReadOnlyCollection { readonly ICollection source; public ReadOnlyCollectionAdapter(ICollection source) => this.source = source; public int Count => source.Count; public IEnumerator GetEnumerator() => source.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }
然后如下使用
Bar(data.AsReadOnly());
你可以非常简单地创建一个组成一个ICollection
while实现的类IReadOnlyCollection
.您还可以创建一个扩展方法来进行包装(从而允许进行泛型类型推断):
public class ReadOnlyCollectionWrapper: IReadOnlyCollection { private ICollection collection; public ReadOnlyCollectionWrapper(ICollection collection) { this.collection = collection; } public int Count { get { return collection.Count; } } public IEnumerator GetEnumerator() { return collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return collection.GetEnumerator(); } } public static class ReadOnlyCollectionWrapper { public static IReadOnlyCollection AsReadOnly (this ICollection collection) { return new ReadOnlyCollectionWrapper (collection); } }