Two significant differences:
Lookupis immutable. Yay 🙂 (At least, I believe the concreteLookupclass is immutable, and theILookupinterface doesn’t provide any mutating members. There could be other mutable implementations, of course.)- When you lookup a key which isn’t present in a lookup, you get an empty sequence back instead of a
KeyNotFoundException. (Hence there’s noTryGetValue, AFAICR.)
They’re likely to be equivalent in efficiency – the lookup may well use a Dictionary<TKey, GroupingImplementation<TValue>> behind the scenes, for example. Choose between them based on your requirements. Personally I find that the lookup is usually a better fit than a Dictionary<TKey, List<TValue>>, mostly due to the first two points above.
Note that as an implementation detail, the concrete implementation of IGrouping<,> which is used for the values implements IList<TValue>, which means that it’s efficient to use with Count(), ElementAt() etc.