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

前端 未结 3 621
借酒劲吻你
借酒劲吻你 2020-12-14 06:12

This code throws an exception on the marked line:

using System;
using System.Linq.Expressions;

namespace ConsoleApplication2
{
    class Program
    {
              


        
相关标签:
3条回答
  • 2020-12-14 06:54

    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

    0 讨论(0)
  • 2020-12-14 07:02

    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.

    0 讨论(0)
  • 2020-12-14 07:02

    Why is it so?

    I don't know why, and honestly was unaware of that change, but taking a quick look at the decompiled code showed that for all similar lambdas inside the class Roslyn generates instance methods in a singleton nested class called <>c like this

    internal class Program
    {
        [CompilerGenerated]
        [Serializable]
        private sealed class <>c
        {
            public static readonly Program.<>c <>9;
            public static Action<int, int> <>9__0_0;
    
            static <>c()
            {
                Program.<>c.<>9 = new Program.<>c();
            }
    
            internal void <Main>b__0_0(int x, int y)
            {
                Console.WriteLine(x + y);
            }
        }
    }
    

    To me this is a breaking change, but I didn't find any information about that.

    What about how to make your code working, I think @Rob answer covers that part.

    0 讨论(0)
提交回复
热议问题