sasfrog
sasfrog

Reputation: 2460

Dynamic Linq and generic objects - Public member 'Select' on type T not found

I'm trying to create a generic method that accepts a collection object, a string representation of the object's type, and a dictionary(of String,String) whose keys contain properties of interest.

I want to then generate a dynamic linq query based on these inputs. It seems though that even after converting the input collection object to a strongly-typed object, dynamic linq won't work - it says Public member 'Select' on type '{T}' not found (where {T} is the strong type).

Here's basically what I've got:

Sub Testing123(ByVal data As Object, ByVal fieldDefs As Dictionary(Of String, String), ByVal myObjectType as String, ByVal myCollectionType As String, ByVal myAssembly As String)

    ' Type of object in the collection
    Dim properties = Type.GetType(myObjectType).GetProperties().Where(Function(p) fieldDefs.ContainsKey(p.Name)).ToList()
    ' Get type of the collection object (data)
    Dim thisType = Type.GetType(String.Format("{0},{1}",myCollectionType,myAssembly))
    ' Create strongly-typed collection object
    Dim data2 = Convert.ChangeType(data, thisType)
    ' Resolve select list from input
    Dim selectVars As String = "new (" & String.Join(", ", fieldDefs.Keys.ToList()) & ")"
    ' materialise dynamic query
    Dim result = data2.Select(selectVars) ' ERROR IS HERE

    For Each r In result
        Debug.Print(r.Title & " " & r.ViewType)
    Next
End Sub

It works OK if I pass a strongly-typed collection object in (e.g. rather than ByVal data As Object, ByVal data as MyStrongType) and do the equivalent dynamic linq query. But it seems that making the input Object, even though the conversion is successful (have confirmed in debug session), I get this error.

Note that the collection types are custom objects (SharePoint CSOM objects, in case that's helpful), not just List(Of T).

Upvotes: 0

Views: 2294

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54417

Thinking about it further, the DLINQ version of Select must actually require an IEnumerable or an IQueryable rather than an IEnumerable(Of T). I've had a quick look and can't find confirmation of that but I think it must be the case or it wouldn't be dynamic. In that case, you can simply cast as that type, which wouldn't require any other changes to your code.

If an IEnumerable is all that's required then use this:

Dim result = DirectCast(data2, IEnumerable).Select(selectVars)

If an IQueryable is required then, as your object probably doesn't implement that already, you'd need this:

Dim result = DirectCast(data2, IEnumerable).AsQueryable().Select(selectVars)

This answer is a bit of an educated guess but it seems logical, so hopefully it's accurate.

Upvotes: 2

Related Questions