问题描述
我知道我不应该在 Func<>
中声明 foreach
,但我想知道这个 C# 代码是否会增加进程内存并导致内存泄漏?
class Foo {
int[] FooA = { 1,2,3,4 };
string result = "";
void myMethod() {
FooA.ToList().ForEach(a => {
Func<int,string> myFunc = myFuncVar => $"Value: {myFuncVar}\n";
result += myFunc(a);
});
MessageBox.Show(result);
}
}
解决方法
使用sharplab之类的反汇编工具很有帮助;
// trim
internal class Foo
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<int,string> <>9__2_1;
internal string <myMethod>b__2_1(int myFuncVar)
{
return string.Format("Value: {0}\n",myFuncVar);
}
}
private int[] FooA;
private string result;
private void myMethod()
{
Enumerable.ToList(FooA).ForEach(new Action<int>(<myMethod>b__2_0));
}
public Foo()
{
int[] array = new int[4];
RuntimeHelpers.InitializeArray(array,(RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
FooA = array;
result = "";
base..ctor();
}
[CompilerGenerated]
private void <myMethod>b__2_0(int a)
{
Func<int,string> func = <>c.<>9__2_1 ?? (<>c.<>9__2_1 = new Func<int,string>(<>c.<>9.<myMethod>b__2_1));
result += func(a);
}
}
// trim
您可以看到您的 lambda (myFuncVar => $"Value: {myFuncVar}\n";
) 已提升为单例实例 (<myMethod>b__2_1
) 上的方法 (<>c.<>9
)。使用 Func 委托 (<>c.<>9__2_1
) 的延迟初始化静态缓存。
所以不,至少在这种情况下,这里实际上没有每次迭代分配。
编译器可以证明您的 lambda 不需要对局部变量的引用,也不需要任何其他实例字段。即使您分配给该 lambda 的变量具有本地范围和生命周期,该 lambda 本身也可以提升为静态生命周期。类似于将字符串字面量分配给变量的方式,但字符串对象具有静态生命周期。