Erreur du compilateur: une arborescence d'expression peut ne pas contenir d'opération dynamique

c# compiler-errors dynamic expression-trees linq

Question

Considérez le code suivant, qui encapsule (plutôt que d'utiliser l'héritage pour des raisons spécifiques) une instance de Dictionary<string, T> et implémente IEnumerable et IQueryable afin qu'il puisse être utilisé avec les requêtes linq:

public class LinqTest<T> : IEnumerable<KeyValuePair<string, T>>, IQueryable<KeyValuePair<string, T>>
{
    private Dictionary<string, T> items = default(Dictionary<string, T>);

    public virtual T this[string key]
    {
        get { return this.items.ContainsKey(key) ? this.items[key] : default(T); }
        set { this.items[key] = value; }
    }

    public virtual T this[int index]
    {
        get { return this[index.ToString()]; }
        set { this[index.ToString()] = value; }
    }

    public Type ElementType
    {
        get { return this.items.AsQueryable().ElementType; }
    }

    public Expression Expression
    {
        get { return this.items.AsQueryable().Expression; }
    }

    public IQueryProvider Provider
    {
        get { return this.items.AsQueryable().Provider; }
    }

    public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
    {
        return this.items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.items.GetEnumerator();
    }
}

J'ai testé ce code comme suit:

public class LinqTest<T> : IEnumerable<KeyValuePair<string, T>>, IQueryable<KeyValuePair<string, T>>
{
    private Dictionary<string, T> items = default(Dictionary<string, T>);

    public virtual T this[string key]
    {
        get { return this.items.ContainsKey(key) ? this.items[key] : default(T); }
        set { this.items[key] = value; }
    }

    public virtual T this[int index]
    {
        get { return this[index.ToString()]; }
        set { this[index.ToString()] = value; }
    }

    public Type ElementType
    {
        get { return this.items.AsQueryable().ElementType; }
    }

    public Expression Expression
    {
        get { return this.items.AsQueryable().Expression; }
    }

    public IQueryProvider Provider
    {
        get { return this.items.AsQueryable().Provider; }
    }

    public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
    {
        return this.items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.items.GetEnumerator();
    }
}

Cela m'indique que o.Value.GetType() == typeof(Guid) ne peut pas être compilé dans l'expression car elle est dynamic .

Cependant, j'ai testé cette théorie avec le code suivant:

public class LinqTest<T> : IEnumerable<KeyValuePair<string, T>>, IQueryable<KeyValuePair<string, T>>
{
    private Dictionary<string, T> items = default(Dictionary<string, T>);

    public virtual T this[string key]
    {
        get { return this.items.ContainsKey(key) ? this.items[key] : default(T); }
        set { this.items[key] = value; }
    }

    public virtual T this[int index]
    {
        get { return this[index.ToString()]; }
        set { this[index.ToString()] = value; }
    }

    public Type ElementType
    {
        get { return this.items.AsQueryable().ElementType; }
    }

    public Expression Expression
    {
        get { return this.items.AsQueryable().Expression; }
    }

    public IQueryProvider Provider
    {
        get { return this.items.AsQueryable().Provider; }
    }

    public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
    {
        return this.items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.items.GetEnumerator();
    }
}

Ceci compile et fonctionne sans TOUTES erreurs, et contient une expression dynamique ... quelqu'un peut-il expliquer et éventuellement indiquer comment je peux corriger mon code?

Remarque: .ForEach est une méthode d'extension non standard qui implémente une boucle foreach.

Réponse acceptée

Le problème est que votre type implémente IQueryable<> . Queryable méthode Queryable est donc choisie par la recherche de membre. Le compilateur tente donc de créer une arborescence d'expression à partir de votre expression lambda ... et c'est ce qui échoue.

L'exemple de dictionnaire réussit car il utilise Enumerable plutôt que Queryable . Il convertit donc l'expression lambda en un délégué.

Vous pouvez réparer votre code en utilisant AsEnumerable :

item.AsEnumerable()
    .Where(o => o.Value.GetType() == typeof(Guid))
    .ForEach(i => Console.WriteLine(i));

Pour être honnête, la raison pour laquelle vous implémentez IQueryable<> n’est pas claire. Une autre option plus simple consisterait simplement à cesser de le faire. Vos données source sont simplement un Dictionary , vous allez donc déjà utiliser LINQ to Objects au lieu de tout ce qui est interrogeable ... Pourquoi introduire IQueryable<> ?




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi