2014-12-15 1 views
5

Рассмотрим следующий код, который оборачивает (а не с помощью наследования по определенным причинам) экземпляром Dictionary<string, T> и реализует IEnumerable и IQueryable, так что он может быть использован с помощью 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(); 
    } 
} 

Я тестировал этот код следующим образом:

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 

Это указывает мне, что o.Value.GetType() == typeof(Guid) не может быть с ompiled в выражение, потому что это dynamic.

Однако, я проверил эту теорию со следующим кодом:

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

компилируется и работает без каких-либо ошибок, а также содержит динамическое выражение ... может кто-нибудь объяснить, и, возможно, указать на то, как я могу исправить мой код?

Примечание:.ForEach - это нестандартный метод расширения, который реализует цикл foreach.

+0

Вы используете это с Linq to Sql? Или просто Linq для объектов? – Will

+0

@Will, просто Linq to Objects (пока) – series0ne

ответ

7

Проблема заключается в том, что ваш тип реализует IQueryable<>, поэтому метод Queryable выбирается путем поиска члена - поэтому компилятор пытается создать дерево выражений из вашего выражения лямбда ... и это то, что терпит неудачу.

Пример словаря преуспевает, потому что он использует Enumerable, а не Queryable, поэтому вместо этого преобразует выражение лямбда в делегат.

Вы можете исправить свой код, используя AsEnumerable:

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

Это не понятно, почему вы реализуете IQueryable<> вообще, если честно - еще один простой вариант был бы просто прекратить делать это. Ваши исходные данные - это всего лишь Dictionary, так что это уже будет использование LINQ для объектов, а не что-нибудь запрашиваемое ... зачем вводить IQueryable<>?

+0

«Зачем вводить IQueryable <> вообще» - потому что я был достаточно глуп, чтобы не исследовать (массовые и абсолютные) различия между IEnumerable и IQueryable и верил в мое незнание что расширения LINQ доступны только для объектов, реализующих IQueryable <>. Большое спасибо за ваш ответ! :-) – series0ne

Смежные вопросы