2009-03-17 5 views
14

Я использовал выражения C#, прежде чем основываться на lamdas, но у меня нет опыта составления их вручную. Учитывая Expression<Func<SomeType, bool>> originalPredicate, я хочу создать Expression<Func<OtherType, bool>> translatedPredicate.C# Как преобразовать выражение <Func <SomeType>> в выражение <Func <OtherType>>

В этом случае SomeType и OtherType имеют одинаковые поля, но они не связаны (нет наследования и не основаны на общем интерфейсе).

Фон: У меня есть реализация репозитория на основе LINQ to SQL. Я проектирую объекты LINQ to SQL для своих объектов модели, чтобы сохранить мою модель в POCO. Я хочу передать выражения в репозиторий (как форму спецификации), но они должны основываться на объектах модели. Но я не могу передать эти выражения в контексте данных, так как он ожидает выражения, основанные на объектах LINQ to SQL.

+1

Ответ в этой теме: http://stackoverflow.com/questions/4601844/expression-tree-copy-or-convert – jeanlou1370

ответ

20

С Expression, самым простым способом с выражения преобразования:

class Foo { 
    public int Value { get; set; } 
} 
class Bar { 
    public int Value { get; set; } 
} 
static class Program { 
    static void Main() { 
     Expression<Func<Foo, bool>> predicate = 
      x => x.Value % 2 == 0; 
     Expression<Func<Bar, Foo>> convert = 
      bar => new Foo { Value = bar.Value }; 

     var param = Expression.Parameter(typeof(Bar), "bar"); 
     var body = Expression.Invoke(predicate, 
       Expression.Invoke(convert, param)); 
     var lambda = Expression.Lambda<Func<Bar, bool>>(body, param); 

     // test with LINQ-to-Objects for simplicity 
     var func = lambda.Compile(); 
     bool withOdd = func(new Bar { Value = 7 }), 
      withEven = func(new Bar { Value = 12 }); 
    } 
} 

Однако обратите внимание, что это будет поддерживаться по-разному различными поставщиками. EF может не понравиться, например, даже если LINQ-to-SQL делает.

Другой вариант - перестроить дерево выражений полностью, используя отражение, чтобы найти соответствующие элементы. Гораздо сложнее.

+0

человек ты гений ... спасибо !!! :) – SteveCl

+0

Я надеюсь, что L2EF понравится это, потому что я преобразовываю выражение из интерфейса в конкретный класс и возвращаю результаты как IQueryable ... как вы думаете, есть способ уменьшить накладные расходы? – IAbstract

+0

+1: Это заставляет меня идти правильным путем, я думаю. Тем не менее, я определенно узнал что-то новое. Я получаю отсутствующие отношения от EF.Я немного поработаю над этим, прежде чем задать новый вопрос. Мне интересно, нужно ли прикреплять таблицы через метод EntityCollection ... – IAbstract

2

Существует неявный способ сделать перевод. Вы должны обернуть существующий делегат внутри лямбды, который создает новый тип от типа аргумента:

var translatedPredicate = x => originalPredicate(OtherTypeFromSomeType(x)) 

Где OtherTypeFromSomeType создает экземпляр OtherType из SomeType аргумента.

+0

+1; избили меня! –

+2

Вопрос касался выражений, а не делегатов. Вы не можете использовать этот подход для вызова подвыражения; он более сложный. –

+0

К сожалению, не читал достаточно внимательно. Во всяком случае, техника в основном одинакова, выражения требуют больше работы (хотя технически мой код все равно работал после первой компиляции 'originalPredicate' и с использованием' Expression <…> 'вместо' var' ;-)). –

3

Существует один другой способ, который я нашел, который также включает в себя перенос оригинального делегата.

Func<T, object> ExpressionConversion<U>(Expression<Func<T, U>> expression) 
{ 
    Expression<Func<T, object>> g = obj => expression.Compile().Invoke(obj); 
    return g.Compile(); 
} 
0

Я была такая же проблема, как вы и я установил его, как это с EF:

var viewModeValue = dbContext.Model.Select(m => new ViewModel{Field = m.Field}).Where(predicate) //predicate is an Expression<Func<ViewModel, bool>> 

Entity Framework знает, как построить правильную команду SQL. Преобразование выражения намного сложнее, потому что оно построено как неизменное и может вызвать нежелательные эффекты времени выполнения, если вы делаете что-то неправильно и, по крайней мере, в моем случае, это не нужно.

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