2010-08-09 8 views
18

Je dirai d'emblée que je fais des choses vraiment effrayantes avec linq sur les données dynamiques. Mais je ne peux pas comprendre pourquoi cette requête ne peut pas compiler:Erreur de compilation Dynamic + linq

Erreur 1 La propriété « <> h__TransparentIdentifier0 » ne peut pas être utilisé avec des arguments de type

 
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); 

    } 
} 

Pour ajouter l'insulte à l'injure, les travaux suivants :

 
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 }; 

Il est seulement quand j'ajoute:

où tag.ReferencedAggregate = null

que je reçois une erreur deux lignes avant:

où entity.Tags = erreur null // COMPILER ICI

Je ne sais pas ce qui se passe

Répondre

12

Si je tente simplement convertir vos appels:

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) 

je reçois une erreur de compilateur différent qui révèle peut-être ce qui se passe:

« Ne peut pas utiliser une expression lambda comme argument à une dynamique opération distribuée sans d'abord l'envoyer à un délégué ou une arborescence d'expression '

Donc je suppose que vous devez surcharger l'opérateur Where.

+3

Merci, c'était tout. J'ai fini de résoudre ceci en utilisant: de tag dans entity.Tags.Where ((Func t.ReferencedAggregate! = Null)) Ugly comme l'enfer. J'ai essayé d'écrire la méthode d'extension, mais je n'arrivais pas à comprendre comment la faire accepter par le CSC. –

1

Le retour de type Anonymous est <> h__TransparentIdentifier0 et est traité par le compilateur lors de la compilation - le problème semble « ordre de préséance dynamique » - ont une lecture ici: Method-missing difficulties in C# 4.0: dynamic vs RealProxy

Je suis juste allé à travers aujourd'hui travailler jusqu'à ar Courrier post. Je vais avoir une petite supposition et dire que le type Anonymous est préparé après l'affectation dynamique :) - le compilateur le sait et vous contrarie.

Le problème disparaît-il si vous utilisez un retour de type régulier? Je suppose que c'est nécessaire.

+0

Rob, Je ne pense pas. Le principal problème est que cela fonctionne pour beaucoup d'autres scénarios. Je n'arrive pas à comprendre pourquoi ça ne marche pas pour ça. Toutes les méthodes LinqOnDynamic renvoient IEnumerable de dynamic, cela ne devrait donc pas poser de problème. On dirait qu'il essaie de faire une forte liaison à une méthode d'extension, mais je ne vois pas comment. –

+0

Ahh - dynamique ne supporte pas ExtensionMethods: http://stackoverflow.com/questions/258988/will-the-dynamic-keyword-in-c4-support-extension-methods Je ne peux pas dire exactement où vous utilisez-le - mais les méthodes d'extension de yah pourraient être le problème. –

+0

Ce n'est pas en cours d'exécution sur dynamique, il s'exécute sur IEnumerable de dynamique C'est un type statique, donc il peut avoir des méthodes d'extension. –

2
 
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 }; 

C'est un peu mieux. Ce n'est pas parfait, mais c'est comme la création - vous ne pouvez aller à plusieurs niveaux avant de vous perdre dans les limbes.