Reputation: 17772
Given the following code, I am having trouble returning a Dictionary.
[JsonProperty]
public virtual IDictionary<Product, int> JsonProducts
{
get
{
return Products.ToDictionary<Product, int>(x => x.Key, v => v.Value);
}
}
public virtual IDictionary<Product, int> Products { get; set; }
I get the following errors..
'System.Collections.Generic.IDictionary' does not contain a definition for 'ToDictionary' and the best extension method overload 'System.Linq.Enumerable.ToDictionary(System.Collections.Generic.IEnumerable, System.Func, System.Collections.Generic.IEqualityComparer)' has some invalid arguments
cannot convert from 'lambda expression' to 'System.Func'
cannot convert from 'lambda expression' to 'System.Collections.Generic.IEqualityComparer
There is nothing special about the Product class. it is simply defined as
class Product
{
public virtual int Id { get; set; }
public virtual String Name { get; set; }
}
Upvotes: 12
Views: 9088
Reputation: 100328
Why do you use
Products.ToDictionary<Product, int>(x => x.Key, v => v.Value)
instead of just
Products.ToDictionary(x => x.Key, v => v.Value)
?
That's because
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector
);
Take a look to the number (3) and types of generic type parameters (Func).
which means that you need to call it:
Products.ToDictionary<KeyValuePair<Product, int>, Product, int>(x => x.Key, v => v.Value);
Upvotes: 18
Reputation: 241741
Don't specify the generic type parameters explicitly. The types in ToDictionary<T1, T2>
are not T1 = TKey
and T2 = TValue
(where TKey
is the type of the key of the resulting dictionary and TValue
is the type of the resulting value in the dictionary).
The overload of ToDictionary
that accepts two generic type parameters has T = TSource
and V = TKey
. Here, TSource = KeyValuePair<Product, int>
. Further, you are invoking the overload of ToDictionary
that has two parameters. The first parameter is a map from T1 -> T2
and the second is an IEqualityComparer<T2>
. But x => x.Key
is not a map from KeyValuePair<Product, int>
to int
and v => v.Value
is not an IEqualityComparer<int>
.
When you don't specify the generic type parameters explicitly, the compiler inspects the types of x => x.Key
and v => v.Value
and looks at the various overloads of ToDictionary
. There are four
ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>)
ToDictionary<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IEqualityComparer<TKey>)
ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>)
ToDictionary<TSource, TKey, TElement>(IEnumerable<TSource>, Func<TSource, TKey>, Func<TSource, TElement>, IEqualityComparer<TKey>)
Note that it can immediately rule out 1. and 4. because they have the wrong number of parameters (2 and 4 respectively whereas you are invoking an overload that needs three parameters (the third is the hidden first parameter because you are invoking an extension method)). It can rule out 2. because the last parameter can not be converted to an IEqualityComparer<T>
for any T
. This leaves the last overload. It is able to deduce that x => x.Key
is a Func<KeyValuePair<Product, int>, Product>
, that v => v.Value
is a Func<KeyValuePair<Product, int>, int>
and therefore that you are invoking
ToDictionary<KeyValuePair<Product, int>, Product, int>(
IEnumerable<KeyValuePair<Product, int>>,
Func<KeyValuePair<Product, int>, Product>,
Func<KeyValuePair<Product, int>, int>
)
If you wanted to specify the type parameters explicitly you would have to say
Products.ToDictionary<KeyValuePair<Product, int>, Product, int>(
x => x.Key,
v => v.Value
);
Upvotes: 1
Reputation: 27515
If you're not actually cloning the Product instances, you can just do:
public virtual IDictionary<Product, int> JsonProducts
{
get
{
return new Dictionary(Products);
}
}
Upvotes: 0