在C#中由lambda创建的委托的生存期是多少?
兰姆达斯很不错,因为他们提供和。不必编写只使用一次的函数,您可以使用lambda 在想它们是如何工作的时候,我直觉地认为它们可能只创建了一次。这启发我创建了一个解决方案,通过使用lambda作为创建它的范围的标识符,它允许创建一个特定的范围 这个实现是有效的,尽管可能有些过分(仍在研究),证明了我的假设是正确的 一个较小的例子:在C#中由lambda创建的委托的生存期是多少?,c#,delegates,lambda,C#,Delegates,Lambda,兰姆达斯很不错,因为他们提供和。不必编写只使用一次的函数,您可以使用lambda 在想它们是如何工作的时候,我直觉地认为它们可能只创建了一次。这启发我创建了一个解决方案,通过使用lambda作为创建它的范围的标识符,它允许创建一个特定的范围 这个实现是有效的,尽管可能有些过分(仍在研究),证明了我的假设是正确的 一个较小的例子: class SomeClass { public void Bleh() { Action action = () => {};
class SomeClass
{
public void Bleh()
{
Action action = () => {};
}
public void CallBleh()
{
Bleh(); // `action` == {Method = {Void <SomeClass>b__0()}}
Bleh(); // `action` still == {Method = {Void <SomeClass>b__0()}}
}
}
class-SomeClass
{
公共空间Bleh()
{
动作动作=()=>{};
}
公共无效CallBleh()
{
Bleh();//`action`={Method={Void b__0()}
Bleh();//`action`still=={Method={Void b__0()}}
}
}
lambda是否会返回一个新实例,或者它是否保证总是相同的?这两种方式都不能保证
根据我对当前MS实施的记忆:
- 不捕获任何变量的lambda表达式是静态缓存的
- 仅捕获“this”的lambda表达式可以在每个实例的基础上捕获,但不是
- 无法缓存捕获局部变量的lambda表达式
- 具有完全相同程序文本的两个lambda表达式没有别名;在某些情况下,它们可能是,但确定它们可能处于的情况将非常复杂
好问题。我没有一个“学术答案”,更多的是一个实际答案:我可以看到编译器优化二进制文件以使用相同的实例,但我永远不会编写假定它“保证”为相同实例的代码
我至少投了你一票,所以希望有人能给你你想要的学术答案。我在回答的时候看到Skeet插嘴了,所以我不会再重复这一点。为了更好地理解您是如何使用这些东西,我建议您熟悉逆向工程工具和IL。将有问题的代码样本和逆向工程提交给IL。它将为您提供大量有关代码如何工作的信息。不保证 快速演示:
Action GetAction()
{
return () => Console.WriteLine("foo");
}
调用两次,执行aReferenceEquals(a,b)
,您将得到true
Action GetAction()
{
var foo = "foo";
return () => Console.WriteLine(foo);
}
打两次电话,做a
ReferenceEquals(a,b)
,你会得到false
根据你的问题和你对Jon答案的评论,我认为你混淆了很多事情。为了确保清楚,请执行以下操作:
- 为给定lambda支持委托的方法始终相同
- 为词汇上出现两次的“相同”lambda支持委托的方法是允许相同的,但实际上在我们的实现中是不同的
- 为给定lambda创建的委托实例可能总是相同的,也可能不总是相同的,这取决于编译器缓存它的智能程度
for(i = 0; i < 10; ++i)
M( ()=>{} )
然后,在实践中,编译器会将其生成为
static void MyAction1() {}
static void MyAction2() {}
static Action ActionCache1 = null;
static Action ActionCache2 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
if (ActionCache2 == null) ActionCache2 = new Action(MyAction2);
Action a2 = ActionCache2;
但是,允许编译器检测两个lambda是否相同并生成
static void MyAction1() {}
static Action ActionCache1 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
Action a2 = ActionCache1;
现在明白了吗?他们所说的“相同效果”到底是什么意思?调用
GetCurrentMethod
显然没有相同的效果……这听起来很对,不过如果lambda“捕获”了泛型方法的类型参数,事情也会变得有点棘手。即使它不使用局部变量或参数,也可能无法在静态字段中缓存。@Eric:使用公共静态本地实例(Func scope)
,其中()=>此
传递给scope。在这种情况下,它仍然返回同一个委托。我现在非常不喜欢“(但不是必需的)”,但是哦,我得到了我的答案@史蒂文:我向你保证,如果你创建两次“()=>this”,它不会返回同一个委托。如果这是你得到的结果,那你就做错了。您如何尝试比较代理的相等性?你知道委托有值,而不是引用相等,对吧?这证实了Jon的回答:“捕获局部变量的lambda表达式不能被缓存”。@Steven还有,“不捕获任何变量的lambda表达式是静态缓存的。”你的第一句话很好。我将使用这个技巧:)非常有用!但我对“允许”有点困惑。你是说现在不是,但将来可能会不同?我运行了代码actiona1=()=>{};动作a2=()=>{};Console.WriteLine(object.ReferenceEquals(a1,a2))“代码>返回false。@Jenix:我说的“允许”是指允许C#编译器的作者编译您的程序,使其返回true
或false
,由编译器作者自行决定。您不能依赖编译器有一个或另一个行为,因为这被记录为允许随时更改。
void MyAction() { this.Bar(); }
...
for(i = 0; i < 10; ++i)
{
M(new Action(this.MyAction));
}
void MyAction() { this.Bar(); }
Action DelegateCache = null;
...
for(i = 0; i < 10; ++i)
{
if (this.DelegateCache == null) this.DelegateCache = new Action ( this.MyAction )
M(this.DelegateCache);
}
Action a1 = ()=>{};
Action a2 = ()=>{};
static void MyAction1() {}
static void MyAction2() {}
static Action ActionCache1 = null;
static Action ActionCache2 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
if (ActionCache2 == null) ActionCache2 = new Action(MyAction2);
Action a2 = ActionCache2;
static void MyAction1() {}
static Action ActionCache1 = null;
...
if (ActionCache1 == null) ActionCache1 = new Action(MyAction1);
Action a1 = ActionCache1;
Action a2 = ActionCache1;