With C# 4 adding some support for dynamic typing one of the first thing that I wanted to do is use it with LINQ.
I want to do this:
dynamic x;
var h = from y in x where y == 1 select y.something;
But I get error messages on both where and select that says
Query expressions over source type ‘dynamic’ or with a join sequence of ‘dynamic’ are not allowed
Major bummer.
But surely there is something I can do. 🙂
*the title of this post starts with LINQ abuse… please don’t comment about how stupid and evil this is. I know it. Instead, consider this an exercise in getting to know C# a little better.
The dynamic type is just sugar for the object type and some attributes to which the compiler pays attention.
Lets use object…
object things = new[] { 0,1,2,3,4,5,6,7, };
var whatIwant = from thing in things
where thing % 2 == 0
select thing;
// or if you like longhand:
var wiw = things.Where(thing => thing%2 == 0).Select(thing => thing);
How does this compile? Well, by making Where and Select resolve to extension methods on object instead of extension methods on IEnumerable<T> (which is what people USUALLY think of when they think LINQ).
public static IEnumerable<dynamic> Select(this object source, Func<dynamic, dynamic> map)
{
foreach (dynamic item in source as dynamic)
{
yield return map(item);
}
}
public static IEnumerable<dynamic> Where(this object source, Func<dynamic, dynamic> predicate)
{
foreach (dynamic item in source as dynamic)
{
if (predicate(item))
yield return item;
}
}
Extension methods on object, then cast to dynamic (extension methods aren’t allowed on dynamic).
It should be short work to fill out whatever LINQ methods are necessary to make whatever LINQ expressions you wish work against dynamic (object) and now you can use LINQ with a source that is typed dynamic.
Well, that is nice!
Can you make it work for SelectMany as well?
I tried a bit, but I couldn’t really get it to work
Never mind, got it to work.
Thanks, that actually solved my problem completely!
Actually, instead of extending object, why not simply extend the non-generic IEnumerable. After all, you are making that presumption internally with Select.
@keith
because we don’t know if it will be IEnumerable. A more real example would be like this:
dynamic x = SomeDynamicResultFromPythonOrSomething();
object o = x;
var result = from i in o where … select …;
The method which returns a dynamic may or may not return a dynamic which ultimately implements IEnumerable. Further more, depending on my implementation of Where, Select, etc. I might not even care if they implement IEnumerable. It may be enough that it returns an object which implements GetEnumerator. Remember that foreach does not require a type implement IEnumerable, just that the GetEnumerator method exist.