If I have a method that requires a parameter that,
Count
propertyWhat should the type of this parameter be? I would choose IList<T>
before .NET 4.5 since there was no other indexable collection interface for this and arrays implement it, which is a big plus.
But .NET 4.5 introduces the new IReadOnlyList<T>
interface and I want my method to support that, too. How can I write this method to support both IList<T>
and IReadOnlyList<T>
without violating the basic principles like DRY?
Edit: Daniel's answer gave me some ideas:
public void Foo<T>(IList<T> list) => Foo(list, list.Count, (c, i) => c[i]); public void Foo<T>(IReadOnlyList<T> list) => Foo(list, list.Count, (c, i) => c[i]); private void Foo<TList, TItem>( TList list, int count, Func<TList, int, TItem> indexer) where TList : IEnumerable<TItem> { // Stuff }
Edit 2: Or I could just accept an IReadOnlyList<T>
and provide a helper like this:
public static class CollectionEx { public static IReadOnlyList<T> AsReadOnly<T>(this IList<T> list) { if (list == null) throw new ArgumentNullException(nameof(list)); return list as IReadOnlyList<T> ?? new ReadOnlyWrapper<T>(list); } private sealed class ReadOnlyWrapper<T> : IReadOnlyList<T> { private readonly IList<T> _list; public ReadOnlyWrapper(IList<T> list) => _list = list; public int Count => _list.Count; public T this[int index] => _list[index]; public IEnumerator<T> GetEnumerator() => _list.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }
Then I could call it like Foo(list.AsReadOnly())
Edit 3: Arrays implement both IList<T>
and IReadOnlyList<T>
, so does the List<T>
class. This makes it pretty rare to find a class that implements IList<T>
but not IReadOnlyList<T>
.
The IReadOnlyCollection interface extends the IEnumerable interface and represents a basic read-only collection interface. It also includes a Count property apart from the IEnumerable members as shown in the code snippet given below.
You are out of luck here. IList<T>
doesn't implement IReadOnlyList<T>
. List<T>
does implement both interfaces, but I think that's not what you want.
However, you can use LINQ:
Count()
extension method internally checks whether the instance in fact is a collection and then uses the Count
property.ElementAt()
extension method internally checks whether the instance in fact is a list and than uses the indexer.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With