¿Por qué un lambda sin captura ha cambiado de un método estático en C# 5 a un método de instancia en C# 6?


Este código lanza 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 encanto) y en la Comunidad VS2015 (lanza la excepción).

Seguí la Fuente de referencia . Net, lo que me llevó a una condición de código que comprueba si el método suministrado 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, lanza, diciendo yo que no suministré el argumento Instance.

¿por Qué es así? ¿Cómo se puede evitar esto para que Expression.Call comience a funcionar de nuevo en new Visual Studio?

Author: Johnbot, 2015-11-27

3 answers

No tengo una respuesta en cuanto a por qué eso es así (reproducido localmente, también).

Sin embargo, la respuesta a:

¿por Qué es así? ¿Cómo se puede evitar esto para que la Expresión.Call would empezar a trabajar de nuevo en 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 para arreglar a.Target

 9
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:50

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. Ver Cambios en el comportamiento del almacenamiento en caché de delegados en Roslyn. Como explico, este es un comportamiento permitido porque los métodos anónimos (como los en cuestión aquí) que no capturan variables tienen menos requisitos de vida útil que los que lo hacen. Esto no significa, sin embargo, que esos métodos deben ser estáticos: esto es simplemente un detalle de implementación.

 21
Author: Peter O.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:38

¿por Qué es así?

No se por qué, y honestamente no estaba al tanto de ese cambio, pero echando un vistazo rápido al código descompilado mostró que para todos los lambdas similares dentro de la clase Roslyn genera instancia métodos en una clase anidada singleton llamada <>c así

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 decisivo, pero no encontré ninguna información al respecto.

Qué hay de cómo hacer que tu código funcione, creo que @Rob answer cubre esa parte.

 4
Author: Ivan Stoev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-27 00:33:45