23

I'll say up front that I am doing some really scary things with linq on dynamic data. But I can't figure out why this query fails to compile:

Error 1 The property '<>h__TransparentIdentifier0' cannot be used with type arguments

public class Program
{
    public static void Main(string[] args)
    {
        var docs = new dynamic[0];
        var q = from doc in docs
                where doc["@metadata"]["Raven-Entity-Name"] == "Cases"
                where doc.AssociatedEntities != null
                from entity in doc.AssociatedEntities
                where entity.Tags != null // COMPILER ERROR HERE
                from tag in entity.Tags
                where tag.ReferencedAggregate != null
                select new {tag.ReferencedAggregate.Id, doc.__document_id};
    }
}

public static class LinqOnDynamic
{
    private static IEnumerable<dynamic> Select(this object self)
    {
        if (self == null)
            yield break;
        if (self is IEnumerable == false || self is string)
            throw new InvalidOperationException("Attempted to enumerate over " + self.GetType().Name);

        foreach (var item in ((IEnumerable) self))
        {
            yield return item;
        }
    }

    public static IEnumerable<dynamic> SelectMany(this object source,
                                                    Func<dynamic, int, IEnumerable<dynamic>> collectionSelector,
                                                    Func<dynamic, dynamic, dynamic> resultSelector)
    {
        return Enumerable.SelectMany(Select(source), collectionSelector, resultSelector);
    }

    public static IEnumerable<dynamic> SelectMany(this object source,
                                                    Func<dynamic, IEnumerable<dynamic>> collectionSelector,
                                                    Func<dynamic, dynamic, dynamic> resultSelector)
    {
        return Enumerable.SelectMany(Select(source), collectionSelector, resultSelector);
    }

    public static IEnumerable<dynamic> SelectMany(this object source,
                                                    Func<object, IEnumerable<dynamic>> selector)
    {
        return Select(source).SelectMany<object, object>(selector);
    }

    public static IEnumerable<dynamic> SelectMany(this object source,
                                                                    Func<object, int, IEnumerable<dynamic>> selector)
    {
        return Select(source).SelectMany<object, object>(selector);

    }
}

To add insult to injury, the following works:

var docs = new dynamic[0];
var q = from doc in docs
        where doc["@metadata"]["Raven-Entity-Name"] == "Cases"
        where doc.AssociatedEntities != null
        from entity in doc.AssociatedEntities
        where entity.Tags != null
        from tag in entity.Tags
        select new { tag.ReferencedAggregate.Id, doc.__document_id };

It is only when I add:

where tag.ReferencedAggregate != null

That I get an error two lines before:

where entity.Tags != null // COMPILER ERROR HERE

Not sure what is going on

3 Answers 3

16

If I try just converting your calls to:

var q = from doc in docs.Where(doc => doc["@metadata"]["Raven-Entity-Name"] == "Cases" || doc.AssociatedEntities != null)
        from entity in doc.AssociatedEntities.Where(entity => entity.Tags != null)

I get a different compiler error which perhaps reveals what is going on:

'Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type'

So I guess you have to overload the Where operator.

1
  • 5
    Thanks, that was it. I ended solving this by using: from tag in entity.Tags.Where((Func<dynamic,bool>)(t => t.ReferencedAggregate != null)) Ugly as hell. I tried writing extension method there, but I couldn't figure out how to make CSC accept it. Commented Aug 10, 2010 at 1:09
3
var q = from doc in docs
        where doc["@metadata"]["Raven-Entity-Name"] == "Cases"
        where doc.AssociatedEntities != null
        from entity in 
            ((IEnumerable<dynamic>)doc.AssociatedEntities)
            .Where(entity => entity.Tags != null)
        from tag in 
            ((IEnumerable<dynamic>)entity.Tags)
            .Where(tag => tag.ReferencedAggregate != null)
        select new { tag.ReferencedAggregate.Id, doc.__document_id };

That's a little better. Not perfect, but it's like inception - you can only go so many levels deep before you get lost in limbo.

2

The Anonymous type return is <>h__TransparentIdentifier0 and is worked up by the compiler at compile-time - the problem appears to "dynamic order of precedence" - have a read here: Method-missing difficulties in C# 4.0: dynamic vs RealProxy

I just went through this today working up a recent post. I'll have a small guess and say that the Anonymous type is prepared after the dynamic assignment :) - the compiler knows this and is thwarting you.

Does the problem go away if you use a regular type return? I'm guess it must.

3
  • Rob, I don't think so. The main problem is that it works for a lot of other scenarios. I can't figure out why it doesn't work for this. All the LinqOnDynamic methods return IEnumerable of dynamic, so that shouldn't be a problem. It looks like it is trying to do strong binding to an extension method, but I don't see how. Commented Aug 9, 2010 at 23:05
  • Ahh - dynamic doesn't support ExtensionMethods: stackoverflow.com/questions/258988/… I can't exactly tell where you're using it - but yah Extension Methods could be the issue.
    – user1151
    Commented Aug 9, 2010 at 23:33
  • This isn't actually running on dynamic, it runs on IEnumerable of dynamic That is a static type, so it can have extension methods. Commented Aug 9, 2010 at 23:46

Not the answer you're looking for? Browse other questions tagged or ask your own question.