我目前正在处理一块需要最少内存分配的代码.
我注意到如果我使用参数的方法编译器更改代码并创建一个新的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; }
提前致谢!
无论是显式使用new SomeDelegate
还是省略它,无论是使用lambda,delegate
关键字还是传递方法组,还是未显示任何可能的解决方案,都无关紧要.在每种情况下,都会创建一个委托对象.编译器通常可以推断它应该在那里,所以它不会强迫你输入它; 但无论如何,该代表的创建仍在发生.(嗯,从技术上讲,你可以传入null
而不是分配一个对象,但是你不能做任何工作,所以我认为忽略这种情况是安全的.)
每个选项之间内存分配的唯一真正区别在于,在给定的匿名方法块中,您将关闭变量(workfinished
).为了创建该闭包,运行时将生成它自己的类型来存储闭包的状态,创建该类型的实例,并将其用于委托,因此所有使用匿名方法的解决方案都在创建一个新对象.(当然,它很小,所以在大多数情况下它不会特别昂贵.)
如果你使用一个不捕获任何东西的lambda表达式,编译器将生成一个静态字段来缓存它.所以使用它,你可以改变Action
为a 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() { ... } }