Disons que nous avons d'une simple citation F #:Génération cotations F # paramétrées
type Pet = { Name : string } let exprNonGeneric = <@@ System.Func(fun (x : Pet) -> x.Name) @@>
La citation résultant est comme:
val exprNonGeneri : Expr = NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], x, PropertyGet (Some (x), System.String Name, []))
Maintenant, je veux généraliser, donc je lieu du type « Pet "and property" Name "Je pourrais utiliser un type arbitraire et une méthode/propriété définie dessus. Voici ce que je suis en train de faire:
let exprGeneric<'T, 'R> f = <@@ System.Func<'T, 'R>(%f) @@> let exprSpecialized = exprGeneric<Pet, string> <@ (fun (x : Pet) -> x.Name) @>
L'expression résultante est maintenant différente:
val exprSpecialized : Expr = NewDelegate (System.Func`2[[FSI_0152+Pet, FSI-ASSEMBLY, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], delegateArg, Application (Lambda (x, PropertyGet (Some (x), System.String Name, [])), delegateArg))
Comme vous pouvez le constater, la différence entre la première et la deuxième expression est que dans le premier cas, la L'expression NewDelegate de niveau supérieur contient PropertyGet, tandis que la deuxième expression enveloppe PropertyGet dans une expression Application/Lambda. Et quand je passe cette expression à un code externe, il ne s'attend pas à une telle structure d'expression et échoue.
J'ai donc besoin d'un moyen de construire une version généralisée de la citation, donc quand elle se spécialise, la citation qui en résulte est une correspondance exacte de < @@ System.Func (fun (x: Pet) -> x.Name) @@ >. Est-ce possible? Ou y-a-t-il seulement un choix pour appliquer manuellement un modèle à un devis généré et le transformer en ce dont j'ai besoin?
MISE À JOUR. Pour contourner ce problème, je l'adaptateur suivant mis en œuvre:
let convertExpr (expr : Expr) = match expr with | NewDelegate(t, darg, appl) -> match (darg, appl) with | (delegateArg, appl) -> match appl with | Application(l, ldarg) -> match (l, ldarg) with | (Lambda(x, f), delegateArg) -> Expr.NewDelegate(t, [x], f) | _ -> expr | _ -> expr | _ -> expr
Il fait le travail - je peux maintenant convertir l'expression du 1er au 2ème forme. Mais je suis intéressé à savoir si cela peut être réalisé de manière simple, sans traverser les arbres d'expression.
Merci pour la réponse et une excellente suggestion. Je suis cependant toujours coincé avec le problème connexe: est-il possible de brancher un simple délégué F # (par exemple fun x -> x.Name) dans un devis générique qui est indépendant du type réel, comme la citation # 2 ci-dessus. Ceci est similaire à ce que font les frameworks moqueurs: ils définissent certaines expressions sans connaître d'interfaces concrètes et injectent des types concrets. Je ne semble pas être capable de réaliser cela en F #. –
@Vagif - Je ne suis pas sûr de comprendre votre question. Pourriez-vous nous donner plus de détails sur ce que vous essayez de faire? – kvb
Je dois envoyer interop entre F # et C#. C# attend l'expression LINQ d'un certain type. Je peux l'écrire en F # de façon codée, mais je veux construire un wrapper générique F # pour cela. Ce wrapper devrait être capable de prendre en entrée des lambdas comme "fun x -> x.Name" et de les convertir en citations. Je commence à penser que ce n'est pas possible dans le cas général. –