gpt4 book ai didi

c# - 匿名方法、范围和序列化

转载 作者:太空狗 更新时间:2023-10-29 23:11:50 24 4
gpt4 key购买 nike

假设我有以下代码:

public class Foo
{
private int x;
private int y;

public Bar CreateBar()
{
return new Bar(x, () => y);
}
}

[Serializable]
public class Bar
{
private int a;
private Func<int> b;

public Bar(int a, Func<int> b)
{
this.a = a;
this.b = b;
}
}

在这种情况下,对象和值的范围会发生什么变化?由于 x 是一个值类型,它按值传递给 Bar,因此,它的范围不需要发生任何事情。但是你怎么了?实际评估 b 时,需要保留 y 的值以返回。是否所有的 Foo 都保留下来以在以后评估 y ?我只能假设 Foo 没有被 GC。

现在假设我们将 Bar 序列化到磁盘,然后再反序列化它。实际连载的是什么?它也序列化了 Foo 吗?在 Bar 被反序列化后,发生了什么魔法,可以对 b 求值?您能解释一下 IL 中发生了什么吗?

最佳答案

更新:无需借助 IL 即可查看实际发生的情况:Using reflector to understand anonymous methods and captured variables


当您使用时:

public Bar CreateBar()
{
return new Bar(x, () => y);
}

你隐含的意思是this.y ;所以就委托(delegate)而言,它是对 Foo引用包括在内。因此,Bar 的实例(通过委托(delegate))保留整个 Foo存活(未被垃圾收集)直到 Bar可供收藏。

特别是,编译器不需要(在这种情况下)生成额外的类来处理捕获的变量;唯一需要的是 Foo实例,因此可以在 Foo 上生成一个方法.如果委托(delegate)涉及局部变量(this 除外),这将更加复杂。

就序列化而言...好吧,我首先要说的是,序列化委托(delegate)是一个非常非常糟糕的主意。然而,BinaryFormatter 走委托(delegate),你可以(理论上)结束序列化 Bar , 一个连载 Foo ,以及一个链接它们的序列化委托(delegate) - 但如果您标记 Foo作为[Serializable] .

但我强调 - 这是一个坏主意。我很少用 BinaryFormatter (出于各种原因),但我看到使用它的人的一个常见问题是“为什么要尝试序列化(某种随机类型)”。通常,答案是“您正在发布一个事件,它正在尝试序列化订阅者”,在这种情况下,最常见的解决方法是将事件的字段标记为 [NonSerialized]。 .


而不是看 IL;另一种调查方法是在 .NET 1.0 模式下使用反射器(即不在匿名方法中交换);然后你可以看到:

public Bar CreateBar()
{
return new Bar(this.x, new Func<int>(this.<CreateBar>b__0));
}
[CompilerGenerated]
private int <CreateBar>b__0()
{
return this.y;
}

如你所见;东西传给了Bar是当前实例 ( <CreateBar>b__0() ) 上隐藏方法(称为 this )的委托(delegate)。所以它当前Foo的实例传递给 Bar .

关于c# - 匿名方法、范围和序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1279101/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com