programación - metodos de instancia c#
¿Por qué una lambda sin captura ha cambiado de una estática en C#5 a un método de instancia en C#6? (3)
Este código arroja una excepción en la línea marcada:
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);
}
}
}
Ahora, he probado este código en VS2013 (funciona como un amuleto) y en VS2015 Community (arroja la excepción).
Seguí el origen de referencia de .Net , lo que me llevó a alguna condición de código que verifica si el método suministrado es IsStatic
o no.
En mi caso, el método que paso ( a.Method
) es estático en VS2013 y por alguna razón no estático (instancia) en VS2015. Si no, arroja, diciéndome que no proporcioné el argumento de Instance
.
¿Por que es esto entonces? ¿Cómo se puede evitar esto para que Expression.Call
vuelva a funcionar en el nuevo Visual Studio?
¿Por que es esto entonces?
No sé por qué, y sinceramente no estaba al tanto de ese cambio, pero echar un rápido vistazo al código descompilado mostró que para todos los lambdas similares dentro de la clase, Roslyn genera métodos de instancia en una clase anidada de singleton llamada <>c
como esta
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);
}
}
}
Para mí, este es un cambio radical, pero no encontré ninguna información sobre eso.
¿Qué hay acerca de cómo hacer que su código funcione? Creo que la respuesta de @Rob cubre esa parte.
No tengo una respuesta sobre por qué eso es así (también se reproduce localmente).
Sin embargo, la respuesta a:
¿Por que es esto entonces? ¿Cómo se puede evitar esto para que Expression.Call vuelva a funcionar en el nuevo Visual Studio?
Puedes hacer esto (funciona en ambos compiladores):
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);
}
Gracias a Jeppe Stig Nielsen por la corrección con respecto a a.Target
Roslyn (el compilador de C # utilizado por VS 2015) cambió todos los métodos lambda a métodos no estáticos, ya sea que capturen variables o no. Consulte Delegar los cambios de comportamiento de caché en Roslyn . Como explico , este es un comportamiento permitido porque los métodos anónimos (como los que están en cuestión aquí) que no capturan variables tienen menos requisitos de por vida que los que sí lo hacen. Esto no significa, sin embargo, que esos métodos deben ser estáticos: esto es simplemente un detalle de implementación.