Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6?

This code throws an exception on the marked line:

using System; using System.Linq.Expressions;  namespace ConsoleApplication2 {     class Program     {         static void Main(string[] args)         {             Action<int, int> a = (x, y) => Console.WriteLine(x + y);              ParameterExpression p1 = Expression.Parameter(typeof(int), "p1");             ParameterExpression p2 = Expression.Parameter(typeof(int), "p2");              // Here is the exception ArgumentNullException.             MethodCallExpression call = Expression.Call(a.Method, p1, p2);         }     } } 

Now, I've tested this code in VS2013 (works like a charm) and in VS2015 Community (throws the exception).

I followed the .Net Reference Source, which led me to some code condition which checkes whether the supplied method IsStatic or not.

In my case, the method I pass (a.Method) is static in VS2013 and for some reason non static (instance) in VS2015. If not, it throws, telling me that I did not supply the Instance argument.

Why is it so? How can this be avoided so that Expression.Call would begin to work again in new Visual Studio?

like image 293
AgentFire Avatar asked Nov 26 '15 22:11

AgentFire


People also ask

Can lambda function be static?

You can't declare the lambda expression static.

What is capture in lambda?

The capture clause is used to (indirectly) give a lambda access to variables available in the surrounding scope that it normally would not have access to. All we need to do is list the entities we want to access from within the lambda as part of the capture clause.


2 Answers

Roslyn (the C# compiler used by VS 2015) changed all lambda methods to non-static methods, whether they capture variables or not. See Delegate caching behavior changes in Roslyn. As I explain, this is an allowed behavior because anonymous methods (like those at issue here) that don't capture variables have fewer lifetime requirements than those that do. This doesn't mean, though, that those methods must be static: this is merely an implementation detail.

like image 107
Peter O. Avatar answered Oct 16 '22 14:10

Peter O.


I don't have an answer as to why that is so (reproduced locally, too).

However, the answer to:

Why is it so? How can this be avoided so that Expression.Call would begin to work again in new Visual Studio?

You can do this (works on both compilers):

Action<int, int> a = (x, y) => Console.WriteLine(x + y);  ParameterExpression p1 = Expression.Parameter(typeof(int), "p1"); ParameterExpression p2 = Expression.Parameter(typeof(int), "p2");  MethodCallExpression call; if (a.Method.IsStatic) {     call = Expression.Call(a.Method, p1, p2); } else {     call = Expression.Call(Expression.Constant(a.Target), a.Method, p1, p2); } 

Thanks to Jeppe Stig Nielsen for fix regarding a.Target

like image 41
Rob Avatar answered Oct 16 '22 14:10

Rob