F # - «Недопустимое выражение свойства» - PullRequest
1 голос
/ 25 апреля 2011

У меня есть этот метод, который принимает Expr в качестве параметра:

member x.HasSeq (expr:Expr<'a -> 'b seq>) = 
    let casted = <@ fun z -> (%expr) z :?> ICollection<'b> @>
    ManyNavPropertyInfo(cfg.HasMany <| toLinq casted)

Я хочу привести 'b seq к ICollection<'b>, который, кажется, работает должным образом, однако, когда он достигает линии, где он собирается преобразовать Expr в LINQ (необходимо сделать это, поскольку cfg.HasMany исключает System.Expression<Func<'a,ICollection<'b>>>) просто выдает исключение, говорящее:

InvalidOperationException:

Выражение 'z => UnboxGeneric (ToFSharpFunc (z => z.Books) .Invoke (z)) 'не является действительным выражение свойства. Выражение должен представлять свойство: C #: 't => t.MyProperty 'VB.Net:' Функция (t) t.MyProperty.

Функция, которую я использую для преобразования Expr в LINQ:

let toLinq (exp : Expr<'a -> 'b>) =
    let linq = exp.ToLinqExpression()
    let call = linq :?> MethodCallExpression
    let lambda = call.Arguments.[0] :?> LambdaExpression
    Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 

Ранее я использовал функцию toLinq без проблем - я думаю, это потому, что я произвел приведение b seq к ICollection<'b>, что оставляет UnboxGeneric в Expr и при передаче Expr в toLinq он просто не знает, что делать с UnboxGeneric - но, конечно, это всего лишь теория, и я вообще не знаю, что делать, чтобы ее решить.

1 Ответ

2 голосов
/ 25 апреля 2011

Ваши рассуждения верны - проблема в том, что метод HasMany распознает только определенные деревья выражений C #, а дерево выражений, которое генерирует ваш код F #, отличается.

Я предполагаю, что EF обрабатывает только регистркогда дерево выражений представляет собой простой доступ к свойству нужного типа - в синтаксисе C # что-то вроде: x => x.Foo (без приведения и т. д.).Я думаю, что лучшим вариантом будет изменить ваш код так, чтобы он также ожидал функцию 'a -> ICollection<'b>.

Если у вас есть какой-то способ построить правильное дерево выражений - например, если пользователь указывает x => x.Foo, вы хотитеверните x => x.FooInternal, тогда вы можете использовать шаблоны и функции для работы с цитатами F #, чтобы перестроить дерево выражений:

let hasSeq (e:Expr<'a -> seq<'b>>) =
  match e with
  | Patterns.Lambda(v, Patterns.PropertyGet(Some instance, propInfo, [])) ->
      printfn "Get property %s of %A" propInfo.Name instance
      // TODO: Use 'Expr.Lambda' & 'Expr.PropGet' to construct
      // an expression tree in the expected format
  | _ -> failwith "Not a lambda!"

... но имейте в виду, что результат должен соответствовать структуре, ожидаемой HasMany.Я предполагаю, что замена действительного свойства, указанного пользователем, другим свойством (например, внутренней версией, имеющей правильный тип) - это почти единственное, что вы можете сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...