anonyme - example lambda expression c#



Le compilateur C#considère-t-il une expression lambda comme une méthode publique ou privée? (3)

En interne, le compilateur devrait traduire les expressions lambda en méthodes. Dans ce cas, ces méthodes seraient-elles privées ou publiques (ou autre chose) et est-il possible de changer cela?


En interne, le compilateur devrait traduire les expressions lambda en méthodes.

Je suppose que par "lambda" vous voulez dire un lambda converti en type délégué. Les Lambdas convertis en types d'arborescence d'expression ne sont certainement pas générés en tant que méthodes.

Le compilateur transforme effectivement de tels lambdas en méthodes, oui. Il n’est pas nécessaire de le faire, mais cela est pratique.

Dans ce cas, ces méthodes seraient-elles privées ou publiques (ou autre chose) et est-il possible de changer cela?

La question est quelque peu incohérente. Supposons que je vous ai dit qu'un lambda était une méthode publique. Il n'a pas de nom accessible depuis C #; Comment voulez-vous profiter de sa publicité? Les modificateurs d'accessibilité s'appliquent aux membres avec des noms. La notion même de domaine d’accessibilité donne le domaine d’un nom lors de la résolution de nom .

En pratique, bien sûr, le compilateur doit générer des bits d’accessibilité pour les métadonnées de la méthode incallable par vous. Les méthodes générées sur les classes de fermeture sont internes, car c’est le moyen le plus pratique de les vérifier de manière vérifiable. Les méthodes générées sans fermeture peuvent être privées.

Encore une fois, rien de tout cela n’est nécessaire, et tous les détails de la mise en œuvre sont susceptibles de changer. Vous ne devriez pas tenter de tirer parti des détails de la génération de code du compilateur.


Ça dépend. Avec la version actuelle de Visual Studio, les méthodes qui implémentent lambdas ne sont jamais publiques, mais elles ne sont pas toujours privées. Un programme simple pour tester certaines versions de lambdas:

public class Program
{
    public static void Main()
    {
        var program = new Program();
        Try("A", program.A);
        Try("B", program.B);
        Try("C", program.C);
        Console.ReadKey();
    }

    private static void Try(string name, Func<Action> generator)
    {
        var mi = generator().Method;
        Console.WriteLine($"{name}: DeclaringType={mi.DeclaringType}, Attributes={mi.Attributes}");
    }

    private Action A() => () => { };
    private Action B() => () => { ToString(); };
    private Action C()
    {
        var c = 1;
        return () => c.ToString();
    }
}

empreintes

A: DeclaringType=Scratch.Program+<>c, Attributes=PrivateScope, Assembly, HideBySig
B: DeclaringType=Scratch.Program, Attributes=PrivateScope, Private, HideBySig
C: DeclaringType=Scratch.Program+<>c__DisplayClass4_0, Attributes=PrivateScope, Assembly, HideBySig

Lambda de A n'a pas de captures. Il est créé en tant que méthode internal d'une classe de fermeture vide.

Le lambda de B témoigne. Il est créé en tant que méthode private de la classe contenante.

Le lambda de c capture c . Il est créé en tant que méthode internal d'une classe de fermeture non vide.

Tout cela est sans papiers et a changé dans le passé, il serait donc bon d'éviter de compter dessus. Ce qui compte, c'est que lorsque vous appelez la méthode anonyme, elle se comporte comme spécifié. Si vous avez besoin de plus que cela, vous ne devriez pas utiliser de méthodes anonymes. Selon ce que vous recherchez, vous pourrez toujours utiliser lambdas, mais avec des arbres d'expression, ou vous devrez peut-être créer des méthodes nommées classiques.


Du livre CLR via C # de Jeffrey Richter

Le compilateur définit automatiquement une nouvelle méthode privée dans la classe

... Le compilateur crée automatiquement le nom de la méthode

... les méthodes anonymes générées par le compilateur finissent toujours par être privées, et la méthode est statique ou non statique selon que la méthode accède à des membres d'instance ou non

Donc, la méthode est déclarée comme private ou internal .

Par exemple le code

class AClass {
    public void SomeMethod() {
        Action lambda = () => Console.WriteLine("Hello World");
        lambda();
    }
}

produira la déclaration IL comme

.field private static class [mscorlib]System.Action 'CS$<>9__CachedAnonymousMethodDelegate1'

Comme vous pouvez le voir, il s’agit private static champ private static .

Notez toutefois que l’expression lambda peut être optimisée si vous modifiez exemple en

class AClass
{
    string a = "Hello World";

    public void SomeMethod()
    {
        Action lambda = () => Console.WriteLine(a);
        lambda();
    }
}

compilateur va l'optimiser et il n'y aurait pas de déclaration lambda du tout

IL_0001:  ldstr      "Hello World"
IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)