1

I've written the following function to check an added/modified record for overlapping time periods in the database:

<Extension> Function ClashRecords(Of T)(Query As IQueryable(Of T), Record As T, _
        KeySelector As Expression(Of Func(Of T, Integer)), 
        FromSelector As Expression(Of Func(Of T, DateTime)), 
        TillSelector As Expression(Of Func(Of T, DateTime))) As IQueryable(Of T)
    Dim key = KeySelector.Invoke(Record)
    Dim fromDate = FromSelector.Invoke(Record)
    Dim tillDate = TillSelector.Invoke(Record)
    Dim criteriaExpr As Expression(Of Func(Of T, Boolean)) = Function(x) KeySelector.Invoke(x) = key And FromSelector.Invoke(x) <= tillDate And TillSelector.Invoke(x) >= fromDate
    Return Query.AsExpandable.Where(criteriaExpr.Expand)
End Function

When calling the function as follows:

Dim de As New DataEntities()
Dim w=New Work With {.WorkerID=-1,.FromDate=New DateTime(2014,3,20,7,0,0),.TillDate=New DateTime(2014,3,20,8,30,0)}
Dim clashing = de.Works.ClashRecords(w,Function(x) x.ActivistID, Function(x) x.FromDate, Function(x) x.TillDate)

I get the following error:

InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.FieldExpression' to type 'System.Linq.Expressions.LambdaExpression'.

I don't see that I am using any field expressions -- ActivistID, FromDate, TillDate are all properties.

I am using EF5 and generated POCO classes.

How can I resolve this?

Update

If I enter criteriaExpr.Expand in the Watch window, I don't get an exception. However, if I enter criteriaExpr.Expand.Compile I get the same exception.

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
  • 1
    I believe the field expressions are created by the compiler for accessing outer variables from an inner function (`criteriaExpr` accesses `KeySelector` etc). This seems to be a bug in LinqKit's `ExpressionExpander` which assumes the target of an invocation is always a `LambdaExpression`. – nmclean May 22 '14 at 15:01
  • In this context, I am posting [this link](http://stackoverflow.com/questions/1928636/how-do-closures-work-behind-the-scenes-c). @nmclean Post this as an answer so I can accept it. – Zev Spitz Jul 17 '14 at 12:36

1 Answers1

2

See: How do closures work behind the scenes? (C#)

If a variable from the outer scope is accessed from an inner function, the compiler creates a hidden type to own the variables as fields. Your criteriaExpr accesses the outer function parameters, so it contains FieldExpressions.

I took a quick look at LinqKit's source code (which you seem to be using judging by the Expand and Compile), and it appears that it doesn't support Invoke on a FieldExpression.

Community
  • 1
  • 1
nmclean
  • 7,564
  • 2
  • 28
  • 37