0
votes

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!

1
Can you post the declarations of the types involved? Perhaps right's source-type's Key and Value properties are of different types? Or maybe the ID s are of different-types? Either of these would cause type-inference errors that are probably real logic-errors.Ani
Key and Value properties are the same type. They are all string. ID of left and right are the same.ByulTaeng

1 Answers

1
votes

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).