0

Well, I have the following scenario:

public class Joins<TOuter, TInner, TResult>
{
    public Expression<Func<TOuter, object>> outerKeySelector;
    public Expression<Func<TInner, object>> innerKeySelector;
    public Expression<Func<TOuter, TInner, object>> resultSelector;

    public IEnumerable<TResult> r;

}

public class Test<T>
{
    public IEnumerable<TResult> Join<TInner, TResult>(
        Expression<Func<T, object>> outerKeySelector,
        Expression<Func<TInner, object>> innerKeySelector,
        Expression<Func<T, TInner, TResult>> resultSelector) where TInner : class
    {
        var join = new Joins<T, TInner, TResult>();
        join.innerKeySelector = innerKeySelector;
        join.outerKeySelector = outerKeySelector;

        return join.r;
    }
}

To create the join method, I relied on the link: http://msdn.microsoft.com/en-us/library/bb534644(v=vs.100).aspx

However, when I try to invoke the method, TInner is not recognized, making the method becomes invalid me returning the following error:

Cannot convert expression type 'type' to return type 'TResult'

Note: The class 'Joins' is purely a test, none of it is definitive and the var 'r' is for testing only, used only to facilitate the return.

Example of intended use:

var test = new Test<User>().Join<Permission>(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id , Area = p.Area });

More details:

As mentioned, TInner is not recognized, so I can not make a call the correct method.

As a test I did so:

var test = new Test<User>().Join<Permission>(u => u.Id, p => p.ToString(), (u, p) => new {Id = u.Id, Name = p.ToString()});

I know p.ToString() is not correct, but is not recognizing the properties of the class indicated (in the case Permission), then put ToString() just to finish writing the method.

EDIT:

I need to use the result in a foreach/for

example:

foreach(var obj in test)
{
    var id = obj.Id;
    var area = obj.Area;
    .
    .
    .
}
Eduardo Carísio
  • 415
  • 1
  • 5
  • 14
  • Can you include an example of how you are trying to call it? – lc. Nov 12 '13 at 14:24
  • Doesn't `Test.Join` require two type arguments? You're also trying to return an anonymous class which isn't going to work without either having the compiler infer `TInner` and `TResult` or using `dynamic` AFAIK. – lc. Nov 12 '13 at 14:35
  • Could you give us an example of how it should be the method? – Eduardo Carísio Nov 12 '13 at 14:40
  • I'm not sure there's a problem with the method. Can you call it without specifying the type arguments for Join: `var test = new Test().Join(u => ...)`? – lc. Nov 12 '13 at 14:44
  • No. That way I get the message: "The type arguments for the method 'x' cannot be inferred from the usage. Try to specify the type arguments Explicitly". – Eduardo Carísio Nov 12 '13 at 16:22
  • Then I think you're stuck either using `dynamic` or creating a concrete class for the result... – lc. Nov 13 '13 at 01:31

1 Answers1

0

To make it work, you should do the following:

 var test = new Test<User>().Join<Permission, object>(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id, Area = p.Area });
 //                                           ^^ (resolve the second type argument as well)     

When you define the following:

public TResult Join<TInner, TResult>

then you should either give compiler a hint which type there will be (instead of any, mentioned as type argument: TInner, TResult) explicitly, or it must be somehow recognized automatically by compiler (and then you can ommit it from explicit definition), but in your case you must do that explicitly.


Have a look of this answer. Even though that question is also related to extension methods, there is a pretty good explanation of the logic with the type arguments to resolve.

EDIT:

But object, for sure, is not the best decision, as you can not do anything with that object later (especially, if that's an anonymous type).

So, you should change it, for instance, in the following way:

    public class Test<T, TInner> where TInner : class where T : class 
    {
        public IEnumerable<TResult> Join<TResult>(

        ...

            Expression<Func<T, TInner, TResult>> resultSelector)

after that you can use it as follows:

var test = new Test<User, Permission>()
                .Join(u => u.Id, p => p.IdUser, (u, p) => new { Id = u.Id, Area = p.Area });

EDIT:

if you need the TInner and TResult to be passed to Join method, that's not really possible. The anonymous class can be resolved only automatically by compiler - you can not specify it explicitly.

So, the only way you can solve it then, as the following:

var test = new Test<User>().Join<Permission, dynamic>(...

that would allow you to use your result then with LinQ .Where( method, however, without intellisense support (unless, you create a concrete class for the Join output).

Community
  • 1
  • 1
CodeIt
  • 117
  • 6
  • Ok. The method "worked", but, my ***TResult*** still not recognized, and in a foreach for example, i can't read de properties of new object =\ – Eduardo Carísio Nov 13 '13 at 18:11
  • What `foreach` do you mean (you should provide an example if you use it somewhere). Also, what do you mean on "recognize TResult"? – CodeIt Nov 13 '13 at 18:44
  • I updated the question. In fact the return is a ***IEnumerable*** object. ***TResult*** would be an unknown object (and when I assume it is of type object, it does not recognize the actual type of the object), informed when the method is invoked (represented by the union in the case of the User class and the Permission class and selecting two fields, Id and Area, resulting in a new object containing the properties Id and Area). But when I try to perform a foreach, the properties are not recognized. – Eduardo Carísio Nov 13 '13 at 19:35
  • If you do some update, you should write "EDIT:/UPDATED:" and then add your new data, because that becomes not clear for people who arlready read your previos thoughts. – CodeIt Nov 13 '13 at 20:38
  • Surely, my mistake. The problem is that I can not change the Test class to have another generic object, it must work within the method. – Eduardo Carísio Nov 13 '13 at 21:11