51

Using AutoMapper, I hit a place where a named argument would've fit very nicely:

.ForMember(s => s.MyProperty, opt => opt.MapFrom(s => BuildMyProperty(s, isAdvanced: false)))

But the compiler yelled at me:

An expression tree may not contain a named argument specification

So I had to revert to:

.ForMember(s => s.MyProperty, opt => opt.MapFrom(s => BuildMyProperty(s, false)))

Does anyone know why the compiler disallows named arguments in this situation?

vcsjones
  • 138,677
  • 31
  • 291
  • 286
Brandon Linton
  • 4,373
  • 5
  • 42
  • 63

1 Answers1

43

Consider the following:

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());

You agree I hope that the last two lines must do exactly the same thing, right? Which is to print NM3.

Now, what expression tree library calls would you like the expression tree conversion to generate that ensure this? There are none! We are therefore faced with the following choices:

  1. Implement the feature in the expression tree library. Add a transformation in the expression tree lowering engine that preserves the order of execution of the named arguments. Implement code in the Compile method that takes the execution order into account.
  2. Make x = ()=>Q(n : N(), m: M()); actually be implemented as x = ()=>Q(M(), N()); and be incompatible with the non-expression-tree version.
  3. Disallow named arguments in expression trees. Implement an error message to that effect.

(1) is nice, but expensive. (2) is a non-starter; we can't in good conscience introduce this kind of "gotcha". (3) is cheap but irritating.

We chose (3).

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    This error message I feel should really be documented to this affect. In other words, searching msdn for the exact error message string should provide us with this clarification. http://social.msdn.microsoft.com/Search/en-US?query=%22An%20expression%20tree%20may%20not%20contain%20a%20named%20argument%20specification%22&ac=8 – payo Apr 12 '12 at 23:17
  • This is excellent - thanks Eric. I had never really taken a look at the differences between `Expression<...>` and `Func<...>` until now. When you say that (1) would be expensive, though, does this mean in terms of development cost or that it would be computationally expensive? – Brandon Linton Apr 13 '12 at 13:51
  • 2
    @BrandonLinton: It would be expensive to develop, test, document and maintain, particularly when compared to the very small benefit it affords. We could have chosen to support it in the beginning -- after all, VB has always had named arguments for method calls -- but we chose not to. – Eric Lippert Apr 13 '12 at 14:36
  • 1
    Isn't there an option 4: "Allow named argument in expression trees as long as they are in the same order"? For `record`s it's somewhat common to use named arguments for the primary constructor in the same order as the definition of the constructor. – DrPhil Aug 22 '22 at 13:42
  • 4
    @DrPhil: Had records existed ten years ago when I wrote this answer, that option might have occurred to me. – Eric Lippert Aug 25 '22 at 00:00