Ido
Ido

Reputation: 188

concatenate a MethodCallExpression on MemberExpression

I wish to Create the following Linq expression using Expression tree:

var result2 = soldiers.OrderByDescending(soldier => soldier.Ranks.OrderBy(r=> r.Date).FirstOrDefault().Date).ToArray() ;

The models are listed at the end of the question

I tried to do the following:

ParameterExpression pe = Expression.Parameter(typeof(Soldier), "soldier");

// e.g soldier.ranks
MemberExpression rank = Expression.Property(pe, "ranks");

ParameterExpression nestedParams = Expression.Parameter(typeof(Rank), "rank");

var dateProperty = typeof(Rank).GetProperty("Date");

// e.g rank.Date
MemberExpression nestedExpression= Expression.MakeMemberAccess(nestedParams, dateProperty);

// e.g rank => rank.date
var orderByExp = Expression.Lambda<Func<Rank, DateTime?>>(nestedExpression, nestedParams);

MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
 new Type[] { typeof(Rank), typeof(DateTime?) },
 rank, ***// i suspect the problem is in this line #110***
 orderByExp);

But the following error has been thorwn:

System.InvalidOperationException: 'No generic method 'OrderByDescending' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. '

As I wrote in the code's comments, I suspect that the problem occurs becuase of line 110. I tried to concatenate the orderBy method on the soldier.ranks property. But perhaps becuase the `soldier.ranks is MemberExpression instead of MethodCallExpression or Queryable, i couldn't preformed that action.

I used both links as reference but could find, anything similler to my problem. * https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/how-to-use-expression-trees-to-build-dynamic-queries

*https://stackoverflow.com/a/11337472/10950549

models:

public class Soldier
{
    public Rank Rank {
        get {
            return this.Ranks.OrderByDescending(m => m.Date).FirstOrDefault();
        }
    }

    public ICollection<Rank> Ranks { get; set; }
}

public class Rank
{
    public int Id { get; set; }

    public DateTime? Date { get; set; }
}

thanks,

Upvotes: 3

Views: 418

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205629

I suspect that the problem occurs because of line 110

MethodCallExpression orderByCallExpression2 = Expression.Call(
typeof(Queryable),
"OrderByDescending",
 new Type[] { typeof(Rank), typeof(DateTime?) },
 rank, ***// i suspect the problem is in this line #110***
 orderByExp);

Nope, the problem is the Queryable 3 lines above:

typeof(Queryable),

It doesn't matter what exact type of expression (member, method call etc.) rank is, the important is what is the type of the result of that expression (i.e. Expression.Type). And the type of soldier.Ranks is ICollection<Rank> - definitely not IQueryable<Rank>, hence the exception.

But as we know, ICollection<T> inherits (is a) IEnumerable<T>, hence oldier.Ranks.OrderBy is actually call to Enumerable.OrderBy rather than Queryable.OrderBy.

With that being said, simply change Queryable to Enumerable in the aforementioned line and this particular problem will be solved.

Upvotes: 3

Related Questions