Reputation: 1269
I wrote a LINQ extension to join 2 tables
public static IEnumerable<ObjectDetail<TLeft, string>> ToDetail<TLeft, TRight, TKey>(this IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TKey> leftProperty, Func<TRight, TKey> rightProperty, Func<TRight, TKey> keyProperty, Func<TRight, TKey> valueProperty, string keySelector)
{
return (from l in left
join r in right on leftProperty(l) equals rightProperty(r) into one
select new
{
l,
one
}).AsEnumerable().Select(q => new ObjectDetail<TLeft, string>
{
Item = q.l,
Meta = q.one.Where(m => keySelector.Contains(keyProperty(m).ToString())).ToDictionary(m => keyProperty(m).ToString(), m => valueProperty(m).ToString())
});
}
The compiler understand the extension well but when I try to write
var result = left.ToDetail(right, l => l.ID, r => r.ID, r => r.Key, r => r.Value, "Key");
I got the following error:
The type arguments for method .ToDetail(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable, System.Func, System.Func, System.Func, System.Func, string)' cannot be inferred from the usage. Try specifying the type arguments explicitly
Then I tried to remove the keyProperty and valueProperty parameters from the extension, it run well without any error. I don't know why, maybe the compiler confused and cannot determine the parameter with the same type?
Any helps would be appreciated!
Upvotes: 0
Views: 650
Reputation: 243061
In your function declaration, you use the same function type for rightProperty
, keyProperty
and valueProperty
arguments, so both of these functions should have a type Func<TRight, TKey>
.
This means that when you call the function, the type of r.ID
, r.Key
and r.Value
must be the same (so that the C# compiler can infer the TKey
type parameter from these two). My guess is that in your example, at least one of these three is different (probably ID
).
(Aside, since you're converting the result of valueSelector
and keySelector
to string using the ToString
method, there is probably no reason why you need to use generic types - a function returning object
should do the trick).
Upvotes: 1