Does the C # compiler treat the lambda expression as a public or private method?

Internally, the compiler must translate lambda expressions into methods. In this case, these methods will be private or public (or something else), and can this be changed?

+47
compiler-optimization c #
Mar 07 '16 at 9:14
source share
4 answers

It depends. In the current version of Visual Studio, methods that implement lambdas are never public, but they are not always private. A simple program to check some versions of 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(); } } 

prints

 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 lambda has no captures. It is created as an internal method for an empty closure class.

B lambda captures this . It is created as a private method of the containing class.

C lambda captures C It is created as an internal method of a nonempty closure class.

All of this is undocumented and has changed in the past, so it would be nice not to rely on it. The important thing is that when you invoke an anonymous method, it behaves as directed. If you need something more, you should not use anonymous methods. Depending on what you need, you can also use lambdas, but with expression trees, or you may need to create regular named methods.

+58
Mar 07 '16 at 9:55
source share

Internally, the compiler must translate lambda expressions into methods.

I assume lambda means lambda converted to a delegate type. Lambdas converted to expression tree types, of course, are not generated as methods.

The compiler really turns such lambdas into methods, yes. He does not need to do this, but it is convenient to do so.

In this case, these methods will be private or public (or something else), and can this be changed?

The question is somewhat incoherent. Suppose I told you that lambda is a public method. It does not have a name accessible from C #; how would you use your publicity? Accessibility modifiers apply to members with names. The very concept of an accessibility domain gives a domain name at the time of name resolution.

In practice, of course, the compiler should generate some accessibility bits for the metadata of the method that is not claimed by you. Methods generated in closure classes are internal, as this is the most convenient way to make them available for testing. Methods created without closing may be private.

Again, none of this is required, and all these implementation details are subject to change. You should not try to take advantage of the details of compiler code generation.

+25
Mar 08 '16 at 5:44
source share

From CLR via C # book by Jeffrey Richter

The compiler automatically defines a new private method in the class

... The compiler automatically creates a method name

... anonymous methods generated by the compiler always end up being private, and this method is either static or non-static on whether the method accesses any members of the instance

Thus, a method is declared as private or internal .

For example, code

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

will issue an IL declaration as

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

As you can see, this is a private static field.

However, note that the lambda expression can be optimized if you change the example to

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

the compiler will optimize it, and there will be no lambda declaration at all

 IL_0001: ldstr "Hello World" IL_0006: call void [mscorlib]System.Console::WriteLine(string) 
+7
Mar 07 '16 at 9:57
source share

As mentioned in @hvd, the difference between a lambda expression uses environmental parameters (closure) or not. See: Why do some C # lambda expressions compile for static methods?

Thus, the question makes sense only for the case of non-compliance, when the lambda expression can be converted to a delegate shell without any external dependencies.

You can pass this generated class (which the delegate basically wraps), and it will always refer to the generated delegate in the defining assembly. That way, you can call it from anywhere if the assembly is referenced.

Just check if the transfer and execution of the action defined in another assembly is performed, although the Action.Method itself Action.Method marked as internal.

 // 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(); } } } 

In another assembly:

 namespace OtherAssembly { public interface IB { void AddAction(Action act); } public class A { public void AddActionTo(IB b) { Action act = () => { }; b.AddAction(act); } } } 
+2
Mar 07 '16 at 9:58
source share



All Articles