Comme vous pouvez le voir dans le code ci-dessous, j’ai déclaré un object Action
comme variable.
Quelqu’un voudrait-il me faire savoir pourquoi ce délégué de méthode d’action se comporte comme une méthode statique?
Pourquoi retourne-t-il true
dans le code suivant?
public static void Main(ssortingng[] args) { Action actionMethod = s => { Console.WriteLine("My Name is " + s); }; Console.WriteLine(actionMethod.Method.IsStatic); Console.Read(); }
C’est probablement parce qu’il n’y a pas de fermetures, par exemple:
int age = 25; Action withClosure = s => Console.WriteLine("My name is {0} and I am {1} years old", s, age); Action withoutClosure = s => Console.WriteLine("My name is {0}", s); Console.WriteLine(withClosure.Method.IsStatic); Console.WriteLine(withoutClosure.Method.IsStatic);
Cela affichera false
pour withClosure
et true
pour withoutClosure
.
Lorsque vous utilisez une expression lambda, le compilateur crée une petite classe pour contenir votre méthode, cela comstackrait quelque chose comme ceci (l’implémentation réelle varie vraisemblablement légèrement):
private class b__0 { public int age; public void withClosure(ssortingng s) { Console.WriteLine("My name is {0} and I am {1} years old", s, age) } } private static class b__1 { public static void withoutClosure(ssortingng s) { Console.WriteLine("My name is {0}", s) } } public static void Main() { var b__0 = new b__0(); b__0.age = 25; Action withClosure = b__0.withClosure; Action withoutClosure = b__1.withoutClosure; Console.WriteLine(withClosure.Method.IsStatic); Console.WriteLine(withoutClosure.Method.IsStatic); }
Vous pouvez voir que les instances Action
résultantes pointent effectivement vers des méthodes sur ces classes générées.
La “méthode d’action” n’est statique que comme effet secondaire de l’implémentation. C’est le cas d’une méthode anonyme sans variables capturées. Comme il n’y a pas de variables capturées, la méthode n’a pas d’exigences de durée de vie supplémentaires au-delà de celles applicables aux variables locales en général. S’il faisait référence à d’autres variables locales, sa durée de vie s’étend à la durée de vie des autres variables (voir la section L.1.7, Variables locales et sec. N.15.5.1, Variables externes capturées , dans la spécification C # 5.0).
Notez que la spécification C # ne parle que des méthodes anonymes converties en “arbres d’expression” et non “classes anonymes”. Bien que l’arborescence des expressions puisse être représentée comme des classes C # supplémentaires, par exemple, dans le compilateur Microsoft, cette implémentation n’est pas requirejse (comme indiqué dans la section M.5.3 de la spécification C # 5.0). Par conséquent, il n’est pas défini si la fonction anonyme est statique ou non. De plus, la section K.6 laisse beaucoup de place aux détails des arbres d’expression.
Le comportement de délégué délégué a été modifié dans Roslyn. Auparavant, comme indiqué, toute expression lambda qui ne capturait pas de variables était compilée dans une méthode static
sur le site d’appel. Roslyn a changé ce comportement. Maintenant, tout lambda, qui capture des variables ou non, est transformé en une classe d’affichage:
Compte tenu de cet exemple:
public class C { public void M() { var x = 5; Action action = y => Console.WriteLine(y); } }
Sortie du compilateur natif:
public class C { [ComstackrGenerated] private static Action CS$<>9__CachedAnonymousMethodDelegate1; public void M() { if (C.CS$<>9__CachedAnonymousMethodDelegate1 == null) { C.CS$<>9__CachedAnonymousMethodDelegate1 = new Action (C.b__0); } Action arg_1D_0 = C.CS$<>9__CachedAnonymousMethodDelegate1; } [CompilerGenerated] private static void b__0(int y) { Console.WriteLine(y); } }
Roslyn:
public class C { [ComstackrGenerated] private sealed class <>c__DisplayClass0 { public static readonly C.<>c__DisplayClass0 CS$<>9__inst; public static Action CS$<>9__CachedAnonymousMethodDelegate2; static <>c__DisplayClass0() { // Note: this type is marked as 'beforefieldinit'. C.<>c__DisplayClass0.CS$<>9__inst = new C.<>c__DisplayClass0(); } internal void b__1(int y) { Console.WriteLine(y); } } public void M() { Action arg_22_0; if (arg_22_0 = C. <>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 == null) { C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 = new Action (C.<>c__DisplayClass0.CS$<>9__inst.b__1); } } }
Déléguer les modifications du comportement de mise en cache dans Roslyn explique pourquoi cette modification a été apscope.
La méthode n’a pas de fermeture et fait également référence à une méthode statique elle-même (Console.WriteLine), donc je m’attendrais à ce qu’elle soit statique. La méthode déclarera un type anonyme englobant une fermeture, mais dans ce cas, elle n’est pas requirejse.
A partir de C # 6, les méthodes d’instance seront toujours utilisées par défaut et ne seront jamais statiques (donc actionMethod.Method.IsStatic
sera toujours faux).
Voir ici: Pourquoi un lambda sans capture est-il passé d’une version statique en C # 5 à une méthode d’instance en C # 6?
et ici: Différence dans l’évaluation de l’expression lambda statique du compilateur CSC et Roslyn?