1

I have this strange behavior of linq at runtime in a c# .NET 4.6.1 project. I'm reusing a dynamic type to hold the result set coming from Dapper queries (not shown here).

Consider the following code:

...
IEnumerable<dynamic> resultSet = await dataSource.GetUserInfos(unlockingUserId, applicationName);
...

The incoming result set contains one row with many different columns.

Later in the code, I'm assigning the resultSet object with the result of another database query:

resultSet = await dataSource.ReleaseLock(userId, unlockingUserId, itemId, sessionId);

This time the row returned from the server still contains one row but only one boolean column named, say 'success'.

The following code:

...
if (resultSet.First().success != true)

fails with the following runtime exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.List' does not contain a definition for 'First'

I have no problem when using another dynamic object for holding the results:

IEnumerable<dynamic> unlocked = await dataSource.ReleaseLock(userId, unlockingUserId, itemId, sessionId);

This time, the following code:

...
if (unlocked.First().success != true)

Works fine.

EDIT : It was a mistake on my side. GetUserInfos was returning dynamic instead of IEnumerable.

  • 5
    See the answer [here](http://stackoverflow.com/questions/5311465/extension-method-and-dynamic-object). – Glorin Oakenfoot Jul 08 '16 at 15:20
  • 2
    There's a huge difference between `IEnumerable foo = ... foo.First()` and `dynamic foo = ... foo.First()`. Is the real problem here that `resultSet` is statically typed as `dynamic`? What does `ReleaseLock` return? – Marc Gravell Jul 08 '16 at 16:07
  • @MarcGravell Good catch Marc, GetUserInfos was returning Task instead of Task>. –  Jul 11 '16 at 08:14

1 Answers1

2

Enumerable.First() is an extension method defined in Enumerable, not a method of List. In reality, they are static methods that are made to look like instance methods through compiler magic. The compiler knows to translate extension method calls to their static equivalent, ie Enumerable.First() becomes Enumerable.First(someEnumerable,...).

When you call First() dynamically though, it is called as a method on the dynamic object. The runtime searches the dynamic methods of the object and can't know that you wanted to call some static method instead.

You may be able to use extension methods if you call them in their static form directly, ie if (!Enumerable.First(unlocked)) ...

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • 1
    Note that post ignores the explanation why `dynamic` is even involved here as OP likely believe that `IEnumerable` should not use runtime binding (even if it is the case)... If you believe that this part is obvious you should have closed question as duplicate of http://stackoverflow.com/questions/5311465/extension-method-and-dynamic-object – Alexei Levenkov Jul 08 '16 at 15:27