Flatten IEnumerable<IEnumerable<>>; understanding generics

独自空忆成欢 提交于 2019-12-03 23:27:09
dlev

First, you don't need Flatten(); that method already exists, and is called SelectMany(). You can use it like this:

IEnumerable<IEnumerable<int>> foo = new [] { new[] {1, 2}, new[] {3, 4} };
var bar = foo.SelectMany(x => x); // bar is {1, 2, 3, 4}

Second, your first attempt doesn't work because generic type inference works only based on the arguments to the method, not generic constraints associated with the method. Since there is no argument that directly uses the J generic parameter, the type inference engine can't guess what J should be, and thus doesn't think that your method is a candidate.

It's edifying to see how SelectMany() gets around this: it requires an additional Func<TSource, TResult> argument. That allows the type inference engine to determine both generic types, since they are both available based solely on the arguments provided to the method.

dlev's answer is fine; I just thought I'd add a little more information.

Specifically, I note that you are attempting to use generics to implement a sort of covariance on IEnumerable<T>. In C# 4 and above, IEnumerable<T> already is covariant.

Your second example illustrates this. If you have

List<List<int>> lists = whatever;
foreach(int x in lists.Flatten()) { ... }

then type inference will reason that List<List<int>> is convertible to IE<List<int>>, List<int> is convertible to IE<int>, and therefore, because of covariance, IE<List<int>> is convertible to IE<IE<int>>. That gives type inference something to go on; it can infer that T is int, and everything is good.

This doesn't work in C# 3. Life is a bit harder in a world without covariance but you can get by with judicious use of the Cast<T> extension method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!