Considérez ce qui suit :
static int M() { Console.Write("M"); return 1; }
static int N() { Console.Write("N"); return 2; }
static int Q(int m, int n) { return m + n; }
...
Func<int> f = ()=>Q(n : N(), m: M());
Expression<Func<int>> x = ()=>Q(n : N(), m: M());
Func<int> fx = x.Compile();
Console.WriteLine(f());
Console.WriteLine(fx());
Vous êtes d'accord j'espère que les deux dernières lignes doivent faire exactement la même chose, n'est-ce pas ? Qui est d'imprimer NM3
.
Maintenant, quels appels de la bibliothèque de l'arbre d'expression voudriez-vous que la conversion de l'arbre d'expression génère pour garantir cela ? Il n'y en a pas ! Nous sommes donc confrontés aux choix suivants :
- Implémentez la fonctionnalité dans la bibliothèque d'arbres d'expression. Ajouter une transformation dans le moteur d'abaissement de l'arbre d'expression qui préserve l'ordre d'exécution des arguments nommés. Implémenter le code dans la bibliothèque
Compile
qui prend en compte l'ordre d'exécution.
- Faire
x = ()=>Q(n : N(), m: M());
peut en fait être mis en œuvre comme x = ()=>Q(M(), N());
et être incompatible avec la version sans arbre d'expression.
- Interdire les arguments nommés dans les arbres d'expression. Implémentez un message d'erreur à cet effet.
(1) est agréable, mais coûteux. (2) est un échec ; nous ne pouvons pas en bonne conscience introduire ce genre de "gotcha". (3) est bon marché mais irritant.
Nous avons choisi (3).