Reputation: 2878
OK, so I am writing some really messy code as the library I am working with is returning dynamic type hierarchies. Some of these types can be unfolded to lists of dynamic types and to enable me to work with these dynamic object hierarchies in LINQ I wrote a little method which basically transforms some dynamic objects to an IEnumerable<dynamic>.
I have this method that returns an IEnumerable<dynamic> but when I try to use it with LINQ I get the error "Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.", however if I cast the methods return value from IEnumerable<dynamic> to IEnumerable<dynamic> (a no-op in my mind), it compiles and works fine.
Can anybody explain this behavior to me?
void Main()
{
Foo(null).Select(value => value); // OK... I was expecting this to work.
dynamic unknown = new ExpandoObject();
Foo(unknown).Select(value => value); //COMPILER ERROR: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type... this was a bit more unexpected.
((IEnumerable<dynamic>)Foo(unknown)).Select(value => value); // OK... this was really unexpected.
}
IEnumerable<dynamic> Foo(dynamic param)
{
yield return "Tranformation logic from param to IEnumerable of param goes here.";
}
Upvotes: 4
Views: 882
Reputation:
The result of Foo(unknown)
is dynamic
, not IEnumerable<dynamic>
. That's because the call to Foo
is resolved dynamically, as unknown
is dynamic
.
To resolve Foo
statically, you can write object unknown = new ExpandoObject();
, or change the call to Foo((object) unknown)
.
What makes this worse is that extension methods are not supported on dynamic
. Extension methods on IEnumerable<T>
can be statically found even if T
is dynamic
, but the C# compiler does not provide a list of active using
namespaces, so if you have plain dynamic
, the runtime doesn't know which classes to search for extension methods. Even if .Select(value => value)
could be made to compile, perhaps by turning it into Func<dynamic, dynamic> projection = value => value;
and then unknown.Select(projection)
(untested), it would still throw an exception at run-time. You'd need to explicitly write Enumerable.Select(unknown, projection)
to make it work.
Upvotes: 4