我目前正在处理需要最少内存分配的一大块代码。
我注意到如果我使用参数的方法编译器更改代码并创建一个新的Action,但是如果我使用匿名方法编译器创建一个委托块,我知道新的Action分配内存,但我对代表不太确定。代表们在使用时会分配内存吗?
我的代码
bool workfinished = false;
void DoWork()
{
MyMethod( CallBack1Work ,()=>{ workfinished = false;});
}
void MyMethod(Action callback1 ,Action callback2)
{
}
void CallBack1Work()
{
}
编译器版本
bool workfinished = false;
void DoWork{
MyMethod( new Action( CallBack1Work ),delegate{
workfinished = false;
});
}
void MyMethod(Action callback1 ,Action callback2)
{
}
void CallBack1Work()
{
}
void DoWork_b01()
{
workfinished = false;
}
提前致谢!
答案 0 :(得分:11)
如果使用不捕获任何内容的lambda表达式,编译器将生成一个静态字段以将其缓存。因此,使用它,您可以将Action
更改为Action<YourClass>
并调用它与this
。所以:
class YourClass
{
private bool workFinished;
public void DoWork()
{
MyMethod(instance => instance.Callback1Work(),
instance => instance.workFinished = false);
}
private void MyMethod(Action<YourClass> callback1,
Action<YourClass> callback2)
{
// Do whatever you want here...
callback1(this);
// And here...
callback2(this);
}
private void Callback1Work()
{
// ...
}
}
在任何实例上第一次调用DoWork
时仅创建委托实例。然后将为所有实例的所有未来调用缓存代理。
不可否认,这是一个实施细节。你总能把它弄清楚:
class YourClass
{
private static readonly Action<YourClass> Callback1 = x => x.Callback1Work();
private static readonly Action<YourClass> Callback2 = x => x.workFinished = false;
private bool workFinished;
public void DoWork()
{
MyMethod(Callback1, Callback2);
}
... code as before ...
}
在你去任何这些长度之前,实际上值得对代码进行分析和基准测试。
另一种选择是坚持Action
,但为代理创建实例变量 - 所以只要你在同一个实例上多次调用DoWork
,没关系:
class YourClass
{
private readonly Action foo;
private readonly Action bar;
private bool workFinished;
public YourClass()
{
foo = Callback1Work;
bar = () => workFinished = false;
}
public void DoWork()
{
MyMethod(foo, bar);
}
public void MyMethod(Action callback1, Action callback2)
{
...
}
private void Callback1Work()
{
...
}
}
答案 1 :(得分:9)
无论是显式使用new SomeDelegate
还是省略它,无论是使用lambda,delegate
关键字,还是传入方法组,还是任何可能的解决方案,都无关紧要所示。在每种情况下,都会创建一个委托对象。编译器通常可以推断它应该在那里,所以它不会强迫你输入它;但无论如何,该代表的创建仍在发生。 (嗯,从技术上讲,你可以传入null
而不是分配一个对象,但是你不能做任何工作,所以我认为忽略这种情况是安全的。)
每个选项之间内存分配的唯一真正区别在于,在给定的匿名方法块中,您将关闭变量(workfinished
)。为了创建该闭包,运行时将生成它自己的类型来存储闭包的状态,创建该类型的实例,并将其用于委托,因此所有使用匿名方法的解决方案都在创建一个新对象。 (当然,它很小,所以在大多数情况下它不会特别昂贵。)