Есть ли особая причина, по которой расширитель LinqKit не может получать выражения из полей?

Я использую библиотеку LinqKit , которая позволяет комбинировать выражения на лету.

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

Рассмотрим следующий фрагмент кода:

private static readonly Expression> _selectMessageViewExpr =
    ( Message msg, int requestingUserId ) =>
        new MessageView
        {
            MessageID = msg.ID,
            RequestingUserID = requestingUserId,
            Body = ( msg.RootMessage == null ) ? msg.Body : msg.RootMessage.Body,
            Title = ( ( msg.RootMessage == null ) ? msg.Title : msg.RootMessage.Title ) ?? string.Empty
        };

Мы объявляем выражение который проецирует сообщение на MessageView (я удалил детали для ясности).

Теперь код доступа к данным может использовать это выражение для получения отдельного сообщения:

var query = CompiledQueryCache.Instance.GetCompiledQuery(
    "GetMessageView",
    () => CompiledQuery.Compile(
        _getMessagesExpr
            .Select( msg => _selectMessageViewExpr.Invoke( msg, userId ) ) // re-use the expression
            .FirstOrDefault( ( MessageView mv, int id ) => mv.MessageID == id )
            .Expand()
        )
    );

Это красиво, потому что то же самое выражение можно повторно использовать и для получения списка сообщений:

var query = CompiledQueryCache.Instance.GetCompiledQuery(
    "GetMessageViewList",
    () => CompiledQuery.Compile(
        BuildFolderExpr( folder )
            .Select( msg => _selectMessageViewExpr.Invoke( msg, userId ) )
            .OrderBy( mv => mv.DateCreated, SortDirection.Descending )
            .Paging()
            .Expand()
        ),
    folder
    );

Как видите, выражение проекции хранится в _selectMessageViewExpr и используется для построения нескольких различных запросов.

Однако я потратил много времени на отслеживание странной ошибки, когда этот код разбился в Expand () позвоните по номеру .
В сообщении об ошибке говорилось:

Невозможно преобразовать объект типа System.Linq.Expressions.FieldExpression в тип System.Linq.Expressions.LambdaExpression .

Это только через некоторое время что я понял, что все работает, когда на выражение ссылается в локальной переменной до его вызова Invoke на :

var selector = _selectMessageViewExpr; // reference the field

var query = CompiledQueryCache.Instance.GetCompiledQuery(
    "GetMessageView",
    () => CompiledQuery.Compile(
        _getMessagesExpr
            .Select( msg => selector.Invoke( msg, userId ) ) // use the variable
            .FirstOrDefault( ( MessageView mv, int id ) => mv.MessageID == id )
            .Expand()
        )
    );

Этот код работает, как ожидалось.

Мой вопрос: :

Есть ли какая-то конкретная причина, по которой LinqKit не распознает Invoke в выражениях, хранящихся в полях? Это просто упущение разработчика, или есть какая-то важная причина, по которой выражения должны быть сначала хранятся в локальных переменных?

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

Спасибо.

26
задан Dan Abramov 3 June 2011 в 10:57
поделиться