AlexZholob
AlexZholob

Reputation: 327

Can't convert ICollection<t> to IEnumerable<t>

I am building the expression tree:

{x => x.principal_info.First().agent_for_property_info}

It works as expected.

In fact, I need to convert it to IEnumerable instead of ICollection as you can see here.

Here is the method that works:

public Expression<Func<T, IEnumerable<K>>> GetGenericExpression<T, K>(bool first = false, params string[] properties)
    {
        var expression = GetNavigationPropertySelector<T, K>(typeof(T), first, properties);

        var expRight = (Expression<Func<T, IEnumerable<K>>>)expression;

        return expRight;
    }

In the expression, I get the valid lambda expression:

{x => x.principal_info.First().agent_for_property_info}

When I am casting:

var expRight = (Expression<Func<T, IEnumerable<K>>>)expression;

I get an exception:

Unable to cast object of 
type 
'System.Linq.Expressions.Expression`1[System.Func`2[SomeModel1,
System.Collections.Generic.ICollection`1[SomeModel]]]' 
to type 
'System.Linq.Expressions.Expression`1[System.Func`2[SomeModel1
,System.Collections.Generic.IEnumerable`1[SomeModel]]]'.

I knew that ICollection inherits from IEnumerable assuming, that it something pretty easy to fix.

I researched a lot but didn't find the solution how to cast ICollection<T> to IEnumerable<T> or if this even possible?

In fact, the compiler can cast it implicitly as these lines are valid:

var queryData1 = new QueryData<contact_info, IEnumerable<property_info>>()
                {
                    WhereClause = expression,
                    SelectClause = info => info.principal_info.First().agent_for_property_info
                };

As this expression is a type of ICollection:

info => info.principal_info.First().agent_for_property_info

Upvotes: 5

Views: 2143

Answers (2)

user365004
user365004

Reputation: 41

The solution here is to cast the result ICollection to IEnumerable:

   Type resultType = typeof(IEnumerable<>).MakeGenericType(elementResultType);
   UnaryExpression ienumerableResultExpression = Expression.MakeUnary(ExpressionType.Convert, resultExpr, resultType);
   var result1 = Expression.Call(
                typeof(Queryable), "Select", new Type[] { elementResultType, elementResultType },
                resultProperty, ienumerableResultExpression );

The compiler seems to convert implicitly for you if you write out the Lambda, but it seems you have to explicitly cast if you use Expressions.

Upvotes: 0

AlexZholob
AlexZholob

Reputation: 327

After a few hours of researching, trying different approaches, I came up with Idea, trying to overcome this exception. So the workaround I use was the suggestion from the comments:

x => x.principal_info.First().agent_for_property_info.Select(x4 => x4)

Here what I have added while building an expression:

var result1 = Expression.Call(
                    typeof(Enumerable), "Select", new Type[] { elementResultType, elementResultType },
                    resultProperty, resultExpr);

I actually didn't find the solution, but if someone will encounter such problem, maybe this answer could save his time.

Upvotes: 1

Related Questions