10

LINQPad example:

void Main()
{
    One(i => PrintInteger(i));
    One(PrintInteger);

    Two(i => PrintInteger(i));
    // Two(PrintInteger); - won't compile
}

static void One(Action<int> a)
{
    a(1);
}

static void Two(Expression<Action<int>> e)
{
    e.Compile()(2);
}

static void PrintInteger(int i)
{
    Console.WriteLine(i);
}

Uncommenting the Two(PrintInteger); line results in an error:

cannot convert from 'method group' to 'System.Linq.Expressions.Expression<System.Action<int>>'

This is similar to Convert Method Group to Expression, but I'm interested in the "why." I understand that Features cost money, time and effort; I'm wondering if there's a more interesting explanation.

Community
  • 1
  • 1
TrueWill
  • 25,132
  • 10
  • 101
  • 150
  • Perhaps it's related to the fact that the compilers can only turn *expression lambdas* into expression trees. Statements and multi-line lambdas are not supported. See: [Expression Trees](http://msdn.microsoft.com/en-us/library/bb397951.aspx) – Kenneth K. Apr 07 '13 at 18:27

3 Answers3

9

Because, in order to get the expression tree, we need a representation of the method in (uncompiled) source form. Lambda expressions are locally available in the source code and therefore are always available uncompiled. But methods may not be from inside the current assembly, and may thus be available only in compiled form.

Granted, the C# compiler could decompile the assembly’s IL code to retrieve an expression tree but as you mentioned, implementing feature costs money, this particular feature isn’t trivial, and the benefits are unclear.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • The compiler doesn't need to decompile the method being called. It only need to synthesize the lambda which is always possible. So the argument of this answer does not hold. – usr Apr 07 '13 at 18:46
  • @usr What do you mean by “it needs to synthesize the lambda”? – Konrad Rudolph Apr 07 '13 at 18:49
  • 1
    The compiler can easily go from `One(PrintInteger)` to `One(i => PrintInteger(i))` by a simple transformation on its syntax tree. This means that there is no fundamental reason why it couldn't be done. – usr Apr 07 '13 at 18:50
  • @usr That transformation doesn’t gain us anything. The whole point of using `Expression` is to gain access to the lambda’s expression tree. Your suggestion avoids the compile error but yields a useless expression tree. In such situations `Expression` would have no advantage over `Func` / `Action`. – Konrad Rudolph Apr 07 '13 at 18:51
  • True, but this is what the OP asked for explicitly and by example. – usr Apr 07 '13 at 18:58
  • @usr The OP asked for the reason why this conversion is forbidden. I gave the reason. That’s all I can do. – Konrad Rudolph Apr 07 '13 at 18:59
  • Well, it is the reason why a different conversion is not possible. But the conversion being asked about *is* possible. – usr Apr 07 '13 at 19:00
  • Well in that case the reason is “the conversion makes no sense” which is a pretty unsatisfactory reply. – Konrad Rudolph Apr 07 '13 at 19:01
3

There is no reason in principle. It could be done this way. The compiler could just create the lambda by itself before converting it (this is obviously always possible - it knows the exact method being called so it can just create a lambda from its parameters).

There is one catch, though. The name of the parameter of your lambda is normally hard-coded into the IL being generated. If there is no lambda, there is no name. But the compiler could either create a dummy name or reuse the names of the method being called (they are always available in the .NET assembly format).

Why didn't the C# team decide to enable this? The only reason that comes to mind is that they wanted to spend their time elsewhere. I applaud them for that decision. I'd rather have LINQ or async than this obscure feature.

usr
  • 168,620
  • 35
  • 240
  • 369
0

In the One example, you are implicitly creating an Action<int> delegate. It's the same as:

One( new Action<int>( PrintInteger ) );

I believe this is in the language to improve the syntax for subscribing to events.

The same thing doesn't happen for Expression<T>, which is why your second example doesn't compile.


EDIT :

It's called a "method group conversion". It's in the C# spec - section 6.6

An implicit conversion (§6.1) exists from a method group (§7.1) to a compatible delegate type

Nick Butler
  • 24,045
  • 4
  • 49
  • 70