Search code examples
c#expressionienumerableexpression-treesicollection

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


Solution

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