Compiler error: expression tree may not contain dynamic operation

Consider the following code that wraps (rather than using inheritance for certain reasons) an instance of Dictionary<string, T> and implements IEnumerable and IQueryable so that it can be used with linq queries:

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

I tested this code as follows:

 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 

This indicates that o.Value.GetType() == typeof(Guid) cannot be compiled into an expression because it is dynamic .

However, I tested this theory with the following code:

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

This compiles and runs without ANY errors and contains a dynamic expression ... can someone explain and possibly indicate how I can fix my code?

Note. .ForEach is a non-standard extension method that implements the foreach loop.

+5
source share
1 answer

The problem is that your type implements IQueryable<> , so the Queryable method is selected by searching for the element - so the compiler is trying to create an expression tree from your lambda expression ... and that fails.

The dictionary example succeeds because it uses Enumerable rather than Queryable , so it converts a lambda expression to a delegate instead.

You can fix your code using AsEnumerable :

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

It's unclear why you even implement IQueryable<> , to be honest - another simple option is to just stop doing it. Your source data is just a Dictionary , so LINQ will already be used for objects, not something based on queries ... why introduce IQueryable<> at all?

+7
source

Source: https://habr.com/ru/post/1209114/


All Articles