为什么没有捕获的 lambda 从 C# 5 中的静态方法更改为 C# 6 中的实例方法?
Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6?
此代码在标记行抛出异常:
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);
}
}
}
现在,我已经在 VS2013(非常有效)和 VS2015 社区(抛出异常)中测试了这段代码。
我遵循了 .Net Reference Source,这让我找到了一些代码条件,它检查提供的方法是否 IsStatic
。
就我而言,我传递的方法 (a.Method
) 在 VS2013 中是静态的,并且出于某种原因在 VS2015 中是 非静态(实例)。如果没有,它会抛出,告诉我我没有提供 Instance
参数。
为什么会这样?如何避免这种情况,以便 Expression.Call
在新的 Visual Studio 中再次开始工作?
我不知道为什么会这样(也在本地转载)。
然而,答案是:
Why is it so? How can this be avoided so that Expression.Call would
begin to work again in new Visual Studio?
您可以这样做(适用于两种编译器):
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);
}
感谢 Jeppe Stig Nielsen 修复了 a.Target
Why is it so?
我不知道为什么,老实说我并没有意识到这个变化,但是快速查看反编译代码表明对于 class Roslyn 中所有类似的 lambda 生成 实例 单例中的方法嵌套 class 调用 <>c
像这样
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);
}
}
}
对我来说这是一个重大变化,但我没有找到任何相关信息。
关于如何使您的代码正常工作,我认为@Rob 的回答涵盖了这一部分。
Roslyn(VS 2015 使用的 C# 编译器)将所有 lambda 方法更改为非静态方法,无论它们是否捕获变量。请参阅 . As I explain,这是一种允许的行为,因为不捕获变量的匿名方法(如此处讨论的那些方法)的生命周期要求比那些捕获变量的要少。但这并不意味着这些方法必须是静态的:这只是一个实现细节。
此代码在标记行抛出异常:
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);
}
}
}
现在,我已经在 VS2013(非常有效)和 VS2015 社区(抛出异常)中测试了这段代码。
我遵循了 .Net Reference Source,这让我找到了一些代码条件,它检查提供的方法是否 IsStatic
。
就我而言,我传递的方法 (a.Method
) 在 VS2013 中是静态的,并且出于某种原因在 VS2015 中是 非静态(实例)。如果没有,它会抛出,告诉我我没有提供 Instance
参数。
为什么会这样?如何避免这种情况,以便 Expression.Call
在新的 Visual Studio 中再次开始工作?
我不知道为什么会这样(也在本地转载)。
然而,答案是:
Why is it so? How can this be avoided so that Expression.Call would begin to work again in new Visual Studio?
您可以这样做(适用于两种编译器):
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);
}
感谢 Jeppe Stig Nielsen 修复了 a.Target
Why is it so?
我不知道为什么,老实说我并没有意识到这个变化,但是快速查看反编译代码表明对于 class Roslyn 中所有类似的 lambda 生成 实例 单例中的方法嵌套 class 调用 <>c
像这样
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);
}
}
}
对我来说这是一个重大变化,但我没有找到任何相关信息。
关于如何使您的代码正常工作,我认为@Rob 的回答涵盖了这一部分。
Roslyn(VS 2015 使用的 C# 编译器)将所有 lambda 方法更改为非静态方法,无论它们是否捕获变量。请参阅