Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Enumerable.ToLookup<>() return an ILookup<,> and not a Lookup<,>?

There is one method in Lookup<,> that is not in ILookup<,>:

public IEnumerable<TResult> ApplyResultSelector<TResult>(
    Func<TKey, IEnumerable<TElement>, TResult> resultSelector);

Why is the return type of Enumerable.ToLookup<>() declared to be ILookup<,> despite the fact that it always seems to return an instance of Lookup<,>? If the return type were instead declared to be Lookup<,>, the above method could be used without a cast.

like image 721
Timwi Avatar asked Oct 03 '10 15:10

Timwi


1 Answers

The best practices for designing public APIs dictate that returning an interface is a better idea than returning a concrete class, because you can then return a different concrete class if you need to. The consumer of the API is not supposed to rely on the returned instance being of a specific type.

As you point out, ToList and ToDictionary return concrete types rather than interfaces. Perhaps the reason for this is that ToList and ToDictionary were meant to return you a copy that you can modify should you want to. Since the IList and IDictionary interfaces do not guarantee you that they are editable (which was possibly a bad idea), the designers decided to return the concrete type.

Imagine a hypothetical ToIList() method. If called on an array, it could be implemented to return you a copy of the array, because arrays implement IList<T>. You might then be surprised to find out that calling Add() throws.

On the other hand, ILookup is a read-only interface, so the above doesn't apply. Hence there is no reason not to follow the best practice, like there is with ToList.

like image 189
Roman Starkov Avatar answered Sep 21 '22 19:09

Roman Starkov