2010-08-09 18 views
18

Dirò in anticipo che sto facendo cose davvero spaventose con linq su dati dinamici. Ma io non riesco a capire perché questa domanda non riesce a compilare:Errore di compilazione Dynamic + linq

di errore 1 La proprietà '<> h__TransparentIdentifier0' non può essere utilizzato con argomenti di tipo

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

    } 
} 

Per aggiungere la beffa al danno, le seguenti opere :

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

E 'solo quando aggiungo:

dove tag.ReferencedAggregate = null

che ottengo un errore due righe prima:

dove entity.Tags = null // Errore del compilatore QUI

Non so cosa sta succedendo

risposta

12

se provo solo convertire le chiamate a:

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) 

ottengo un errore di compilazione diversa che rivela forse quello che sta succedendo:

'Non è possibile utilizzare un'espressione lambda come argomento di un modo dinamico operazione inviata senza prima lanciarla a un albero delegato o di espressione '

Quindi immagino che sia necessario sovraccaricare l'operatore Where.

+3

Grazie, era così. Ho risolto il problema utilizzando: dal tag in entity.Tags.Where ((Func ) (t => t.ReferencedAggregate! = Null)) Brutto da morire. Ho provato a scrivere il metodo di estensione lì, ma non sono riuscito a capire come rendere CSC accettarlo. –

1

Il tipo di ritorno anonimo è <> h__TransparentIdentifier0 e viene lavorato dal compilatore a tempo di compilazione - il problema sembra "ordine dinamico di precedenza" - hanno un letto qui: Method-missing difficulties in C# 4.0: dynamic vs RealProxy

ho appena passato attraverso questo oggi lavoro fino ar post ecent. Avrò una piccola ipotesi e dirò che il tipo Anonimo è preparato dopo l' l'assegnazione dinamica :) - il compilatore lo sa e ti sta ostacolando.

Il problema scompare se si utilizza un ritorno di tipo normale? Credo che sia necessario.

+0

Rob, Io non la penso così. Il problema principale è che funziona per molti altri scenari. Non riesco a capire perché non funzioni per questo. Tutti i metodi LinqOnDynamic restituiscono IEnumerable di dynamic, quindi non dovrebbe essere un problema. Sembra che stia cercando di eseguire un forte binding a un metodo di estensione, ma non vedo come. –

+0

Ahh: dynamic non supporta ExtensionMethods: http://stackoverflow.com/questions/258988/will-the-dynamic-keyword-in-c4-support-extension-methods Non riesco a dire esattamente dove lo stiamo usando, ma i metodi di estensione potrebbero essere il problema. –

+0

In realtà non funziona su dinamico, viene eseguito su IEnumerable di dynamic Questo è un tipo statico, quindi può avere metodi di estensione. –

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

Questo è un po 'meglio. Non perfetto, ma è come se fosse un inizio: puoi solo andare a molti livelli in profondità prima di perderti nel limbo.