Compilerfehler: Eine Ausdrucksbaumstruktur darf keine dynamische Operation enthalten

c# compiler-errors dynamic expression-trees linq

Frage

Betrachten Sie den folgenden Code, der eine Instanz von Dictionary<string, T> IEnumerable (statt Vererbung aus bestimmten Gründen zu verwenden) und IEnumerable und IQueryable implementiert, sodass sie mit linq-Abfragen verwendet werden kann:

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

Ich habe diesen Code wie folgt getestet:

LinqTest<dynamic> item = new LinqTest<dynamic>();
item["a"] = 45;
item["b"] = Guid.NewGuid();
item["c"] = "Hello World";
item["d"] = true;

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

//Compiler error: An expression tree may not contain a dynamic operation

Dies zeigt mir, dass o.Value.GetType() == typeof(Guid) nicht in den Ausdruck kompiliert werden kann, da es dynamic .

Ich habe diese Theorie jedoch mit folgendem Code getestet:

Dictionary<string, dynamic> item = new Dictionary<string, dynamic>();
item["a"] = 45;
item["b"] = Guid.NewGuid();
item["c"] = "Hello World";
item["d"] = true;

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

Dies kompiliert und läuft ohne irgendwelche Fehler und enthält einen dynamischen Ausdruck ... kann jemand erklären, und möglicherweise darauf hinweisen, wie ich meinen Code beheben kann?

Hinweis: .ForEach ist eine nicht standardmäßige Erweiterungsmethode, die eine foreach-Schleife implementiert.

Akzeptierte Antwort

Das Problem ist, dass Ihr Typ IQueryable<> implementiert, so dass die Queryable Methode von der Member-Suche ausgewählt wird - der Compiler versucht also, eine Ausdrucksbaumstruktur aus Ihrem Lambda-Ausdruck zu erstellen ... und das schlägt fehl.

Das Wörterbuchbeispiel ist erfolgreich, da es Enumerable statt Queryable verwendet. Enumerable konvertiert es den Lambda-Ausdruck in einen Delegate.

Sie können Ihren Code mit AsEnumerable :

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

Es ist nicht klar, warum Sie IQueryable<> überhaupt implementieren, um ehrlich zu sein - eine andere einfachere Option wäre einfach, damit aufzuhören. IQueryable<> Ihre Quelldaten nur ein Dictionary , wird LINQ to Objects bereits verwendet, anstatt irgend etwas, das auf IQueryable<> basieren könnte. Warum sollte IQueryable<> überhaupt eingeführt werden?



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum