30 votes

Le compilateur a généré un code incorrect pour les méthodes anonymes [MS BUG FIXED]

Voir le code suivant:

public abstract class Base
{
    public virtual void Foo<T>() where T : class
    {
        Console.WriteLine("base");
    }
}

public class Derived : Base
{
    public override void Foo<T>()
    {
        Console.WriteLine("derived");
    }

    public void Bang()
    {
        Action bang = new Action(delegate { base.Foo<string>(); });
        bang();    //VerificationException is thrown
    }
}

new Derived().Bang(); déclenche une exception. À l'intérieur de l'généré CIL de la méthode Bang j'ai eu:

call instance void ConsoleApp.Derived::'<>n__FabricatedMethod1'<string>()

et la signature de l'généré par le compilateur de la méthode:

method private hidebysig 
    instance void '<>n__FabricatedMethod1'<T> () cil managed 
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )       
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void ConsoleApp.Base::Foo<!!T>()
    IL_0006: ret
}

Je pense que le code correct doit être '<>n__FabricatedMethod1'<class T>. Est-ce un bug? Par la manière, sans l'aide d' delegate{ }(expression lambda est la même), le code fonctionne très bien avec la syntaxe des sucres.

Action good = new Action(base.Foo<string>());
good();  //fine

EDIT je suis en utilisant VS2012 RTMRel dans windows8 RTM, .net framework 4.5

MODIFIER Ce bug est maintenant corrigé: http://connect.microsoft.com/VisualStudio/feedback/details/766845/vs2012-the-compiler-generated-incorrect-codes-for-anonymous-methods

3voto

Danny Chen Points 14781

1voto

Ondra Points 883

Au premier abord - C'est une façon possible de résoudre ce problème, mais probablement pas la réponse à votre question. (Mais les commentaires n'ont pas de code de mise en forme)

Je crois que c'est de ce type: Externe Variable Piège, parce que vous êtes à l'aide de Foo() la méthode de la variable et il y a un bug (ou peut-être une fonction) dans .NET

J'ai essayé de changer Bang() la méthode pour ce

public void Bang()
{
    Action baseMethod = base.Foo<string>;
    Action bang = new Action(delegate { baseMethod(); });
    bang();    //VerificationException is thrown
}

Et il fonctionne et le résultat est "de base"

J'espère que ça aide un peu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X