47 votes

Le compilateur C# traiter une expression lambda en tant que public ou privé de la méthode?

En interne, le compilateur doit être la traduction des expressions lambda de méthodes. Dans ce cas, est-ce que ces méthodes soient privées ou publiques (ou autre chose) et est-il possible de changer cela?

57voto

hvd Points 42125

Il dépend. Avec la version actuelle de Visual Studio, les méthodes à mettre en œuvre les lambdas ne sont jamais en public, mais ils ne sont pas toujours de nature privée. 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();
    }
}

imprime

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

As'lambda n'ont pas de capture. Elle est créée comme un internal méthode de vide de fermeture de classe.

Bs'lambda capture this. Il est créé en tant que private méthode de la classe conteneur.

Cs'lambda capture c. Elle est créée comme un internal méthode de non-vide de fermeture de classe.

Tout cela est sans-papiers et qui a changé dans le passé, de sorte qu'il serait bon d'éviter de compter sur elle. Ce qui importe, c'est que lorsque vous appelez la méthode anonyme, il se comporte comme prévu. Si vous avez besoin de rien de plus que cela, vous ne devriez pas être à l'aide de méthodes anonymes. En fonction de ce que vous êtes après, vous pourriez encore être en mesure d'utiliser les lambdas, mais avec des arbres d'expression, ou vous pourriez avoir besoin de créer régulièrement nommé méthodes à la place.

25voto

Eric Lippert Points 300275

En interne, le compilateur doit être la traduction des expressions lambda de méthodes.

Je suppose que par "lambda" tu veux dire qu'un lambda converti en type de délégué. Les Lambdas converti à l'expression des types d'arbres sont certainement pas généré que des méthodes.

Le compilateur ne fait tourner ces lambdas dans les méthodes, oui. Il n'y a pas d' exigence qu'il le fait, mais c'est pratique.

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

La question est quelque peu incohérent. Supposons que je vous ai dit qu'un lambda est une méthode publique. Il n'a pas de nom accessible à partir de C#; comment voulez-vous tirer parti de son public-ness? L'accessibilité des modificateurs s'appliquent aux membres avec des noms. La notion même de l'accessibilité de domaine donne le domaine d'un nom lors de la résolution de nom.

Dans la pratique, bien sûr, le compilateur doit générer de l'accessibilité bits pour les métadonnées de la uncallable-par-vous la méthode. Méthodes générées lors de la fermeture de classes sont à l'intérieur, car c'est le moyen le plus pratique de faire usage d'entre eux vérifiables. Méthodes générées sans les fermetures peuvent être privés.

Encore une fois, rien de tout cela est nécessaire, et tout cela est de la mise en œuvre détail de la réserve de modifications. Vous ne devriez pas être tenter de prendre avantage de la génération de code les détails du compilateur.

7voto

NikolayKondratyev Points 2215

À partir du CLR via C# livre de Jeffrey Richter

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

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

... les méthodes anonymes généré par le compilateur toujours être privé, et la méthode est statique ou non en fonction si la méthode accède à tous les membres de l'instance

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

Par exemple le code

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

va produire la déclaration comme IL

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

Comme vous pouvez le voir il est private static champ.

Cependant remarquer que la lambda expression peut être optimisée, si vous modifiez l'exemple de

class AClass
{
    string a = "Hello World";

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

compilateur d'optimiser et il n'y aurait pas de lambda déclaration à tous les

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

2voto

Benji Wa Points 77

@Hvd mentionné il y a une différence entre une expression lambda utilise des paramètres de son environnement (fermeture des cas) ou pas. Voir: Pourquoi certaines expressions lambda C# compiler en statique méthodes?

Donc, la question n'a de sens que pour la non-fermeture des cas lorsque la lambda expression peut être convertie en un délégué wrapper sans avoir à l'extérieur de dépendances.

Vous pouvez passer cette classe générée (qui, en gros, enveloppements d'un délégué) et il va toujours se référer à l'généré délégué dans la définition de l'assemblée. De sorte que vous pouvez l'appeler de n'importe où si l'assemblée est référencé.

Juste vérifié que la transmission et l'exécution d'une Action définie dans une autre assemblée fonctionne bien que l' Action.Method lui-même est marqué interne.

// Main, first assembly
namespace ConsoleApplication1
{
    public class B : IB
    {
        Action _action;
        public void AddAction(Action act)
        {
            _action = act;
        }

        public void Invoke()
        {
            Console.WriteLine(_action.Target);
            Console.WriteLine("Is public: {0}", _action.Method.IsPublic);
            _action();
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            var a = new A();
            var b = new B();
            a.AddActionTo(b);
            b.Invoke();

            Console.ReadKey();
        }
    }
}

Dans une autre assemblée:

namespace OtherAssembly
{
    public interface IB
    {
        void AddAction(Action act);
    }

    public class A
    {
        public void AddActionTo(IB b)
        {
            Action act = () => { };
            b.AddAction(act);
        }
    }
}

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