在内部,编译器应该将lambda表达式转换为方法。在那种情况下,这些方法是私有的还是公共的(或其他),是否有可能改变它?C#编译器是否将lambda表达式视为公共或私有方法?
回答
这取决于。使用当前版本的Visual Studio,实现lambda表达式的方法从不公开,但它们并不总是私有的。一个简单的程序来测试lambda表达式的一些版本:
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();
}
}
打印
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
的拉姆达没有任何捕获。它创建为空闭包类的internal
方法。
B
's lambda captures this
。它创建为包含类的private
方法。
C
的lambda捕获c
。它创建为非空的闭包类的方法internal
。
所有这些都是无证的,并且在过去发生了变化,所以避免依赖它是件好事。重要的是,当你调用匿名方法,它的行为如指定。如果你需要的不仅仅是这些,你不应该使用匿名方法。根据你以后的情况,你可能仍然可以使用lambda表达式,但是使用表达式树,或者你可能需要创建常规的命名方法。
很好的答案。但是,捕获与方法的可见性有什么关系?如果'A'设置为'private'(或'B'设置为'internal'),会出现什么问题? – haim770
@ haim770包含匿名方法的方法需要能够访问该方法以构建委托。如果匿名方法是作为同一个类的成员创建的,那么它可以是'private',因为方法可以访问他们自己类的私有方法。如果匿名方法是作为不同类的成员创建的,那么它至少需要'内部',因为方法不能访问其他类的私有方法。提高可视性(使所有内部功能都成为可能)将成为可能,但没有理由让它看起来比需要的更清晰。 – hvd
请注意,生成的闭包类是私有的,因此,从外部看,该方法是*私有*。 – svick
从通过C#书杰弗里里希特
编译器自动定义在类
一个新的私有方法的CLR ...编译器会自动为您
创建方法的名称...由编译器生成的匿名方法总是以私有方式结束 ,该方法是静态的还是非静态的,具体取决于 关于该方法是否访问任何实例成员
因此该方法被声明为private
或internal
。
例如代码
class AClass {
public void SomeMethod() {
Action lambda =() => Console.WriteLine("Hello World");
lambda();
}
}
会产生IL声明作为
.field private static class [mscorlib]System.Action 'CS$<>9__CachedAnonymousMethodDelegate1'
正如你可以看到它是private static
字段。
不过,请注意lambda表达式可以优化,如果你改变例子
class AClass
{
string a = "Hello World";
public void SomeMethod()
{
Action lambda =() => Console.WriteLine(a);
lambda();
}
}
编译器优化,并作为@hvd提到的有有将在所有
IL_0001: ldstr "Hello World"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
没有拉姆达声明lambda表达式之间的区别使用来自其周围环境的参数(闭包情况)或不使用。见:Why do some C# lambda expressions compile to static methods?
所以这个问题只对非关闭情况有意义,当lambda表达式可以转换成一个委托包装没有任何外部依赖。
您可以将生成的类(基本上包装委托)传递给它,它将始终引用定义程序集中生成的委托。所以如果程序集被引用,你可以从任何地方调用它。
刚刚证实,传递并执行另一个程序集中定义的动作,虽然Action.Method
本身标记为内部。
// 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();
}
}
}
在其它组件:
namespace OtherAssembly
{
public interface IB
{
void AddAction(Action act);
}
public class A
{
public void AddActionTo(IB b)
{
Action act =() => { };
b.AddAction(act);
}
}
}
在内部,编译器应转换lambda表达式的方法。
我假设“lambda”是指将lambda转换为委托类型。转换为表达式树的Lambdas肯定不是作为方法生成的。
编译器确实将这种lambda表达式转换为方法,是的。它没有要求它这样做,但这样做很方便。
在这种情况下,这些方法是私有的还是公共的(或其他),是否有可能改变这种情况?
这个问题有些不一致。假设我告诉过你,lambda是一种公共方法。它没有可从C#访问的名称;你将如何利用其公共性?辅助功能修饰符适用于具有名称的成员。可访问性域的概念给出了域名名称在名称分辨率。
在实践中,当然编译器必须为不可调用的方法的元数据生成一些可访问性位。在闭包类上生成的方法是内部的,因为这是使它们可以被验证的最方便的方法。不使用闭包生成的方法可以是私有的。
再一次,这些都不是必需的,所有这些都是实施细节可能会发生变化。您不应该试图利用编译器的代码生成细节。
- 1. Lambda表达式:编译器行为
- 2. 的java lambda表达式没有编译
- 3. 与方法公共方法与私有
- 4. 如何将表达式树编译为可调用方法,C#?
- 5. 是否有用于私有公共虚拟方法的用例?
- 6. 以编程方式将变量从公共更改为私人
- 7. C是否使用lambda表达式?
- 8. 私有或公共MSMQ
- 9. 将lambda表达式翻译为表达式树
- 10. C#编译器看到Fluent语法或查询表达式?
- 11. 是否有必要将方法定义为“公共”?
- 12. Rhino Mocks验证私有方法是从公共方法调用
- 13. 包私有类中的公共方法
- 14. 继承和公共/私有方法
- 15. 是否有angular2的流lambda表达式?
- 16. 将C#lambda表达式转换为VB
- 17. Lambda表达式不会编译
- 18. 缓存编译的lambda表达式
- 19. 是否有可能将方法属性从公共私有方法更改为私有方法,并且可以从类内部返回运行时方法?
- 20. 翻译lambda表达式到方案
- 21. 用方法组替换Lambda表达式时发生编译器错误
- 22. 在C#中是否有方法通过插件覆盖私有或公共函数?
- 23. 将私有或受保护的方法转换为公开
- 24. Lambda表达式来检查值是否为空或等于
- 25. 如何将lambda表达式传递给期望lambda表达式的方法?
- 26. 是否有编译为机器代码的C C++ C#编译器
- 27. 为多个表创建公共相关表是否好方法?
- 28. C++ lambda表达式
- 29. C#Lambda表达式
- 30. 如何检查C#lambda表达式是否为“空”?
afaik编译器创建一个包含此lambda作为方法的整个类。所以为了能够称呼它,它至少应该是“内部”的。但我不是编译器专家。 –
@RenéVogt这取决于lambda是否捕获任何东西。如果没有,封闭课程就不需要了。 – hvd
如果它是公开的,你会怎样称呼它?它没有任何人知道的名字,除了编译器。除了包含类以外,任何人都不会使用它,所以没有理由使它成为私有的。 –