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?
Réponses
Trop de publicités?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
A
s'lambda n'ont pas de capture. Elle est créée comme un internal
méthode de vide de fermeture de classe.
B
s'lambda capture this
. Il est créé en tant que private
méthode de la classe conteneur.
C
s'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.
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.
À 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)
@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);
}
}
}