I am using using Microsoft .NET Framework 4.0.
I have run into this using Aggregate on a Dictionary<T, List<T>>
to extract the set of type T
values used across all type List<T>
lists in the dictionary. Here is the simplest case I could come up with that exhibits the same behaviour.
First, as the documentation states, the following does work:
var set = new HashSet<int>();
var list = new LinkedList<int>();
var newSet = set.Union(list);
That is, I can call Union
on a HashSet
with a List
as the argument (since it implements IEnum开发者_如何学Cerable
).
Whereas, the equivalent expression within a Func
argument of the LINQ Aggregate
expression produces an error (precompiler at least):
new List<int>[] { new List<int>() }.Aggregate(new HashSet<int>(), (acc, list) => acc.Union(list));
It expects the argument of Union to be HashSet, and will cooperate if it is given one, contrary to its behaviour outside LINQ/Func expressions.
The real world example I was using when I came across the problem was:
public AdjacencyListGraph(Dictionary<TVertex, LinkedList<TVertex>> adjacencyList)
{
var vertices = adjacencyList.Aggregate(new HashSet<TVertex>(),
(vertices, list) => vertices.Union(list.Value));
}
Which complains that it cannot convert IEnumerable<TVertex>
to HashSet<TVertex>
...
The problem here is in your understanding of the Select
method. The lambda passed in does not recieve the list but instead elements of the list. So the variable you've named list
is in fact of type int
which is not compatible with Union
.
Here is a more explicit example of what you're trying to do
new List<int>().Select( (int list) => new HashSet<int>().Union(list));
With the type infererence removed it's much clearer why this doesn't work.
The problem actually lies in trying to replace the accumulator type of HashSet with the IEnumerable, .Union method doesn't add items to HashSet, but returns the new IEnumerable on the resulting union.
You should change your code to the following:
// select from keys
var vertices = new HashSet<TVertex>(adjacencyList.Keys);
or
// select from values
var vertices = new HashSet<TVertex>(adjacencyList.SelectMany(dictEntry => dictEntry.Value));
new List<int>().Select(list => new HashSet<int>().Union(list));
I think you would expect to use SelectMany
here, unless you want the result to be IEnumerable<IEnumerable<T>>
.
精彩评论