Ste*_*ser 5 c# delegates scope anonymous-methods
假设我有以下代码:
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,因此,不需要对其范围进行任何操作.但是y会发生什么?当实际评估b时,y的值需要保持不变.是不是所有的Foo都会在以后评估y?我只能假设Foo不是GC.
现在让我们说我们将Bar序列化为磁盘,然后再对其进行反序列化.什么实际上被序列化?它是否也将Foo序列化?是什么魔法发生了以便在反序列化后可以评估b?你能解释IL中发生的事情吗?
更新:看看实际发生的事情而不必诉诸于IL:使用反射器来理解匿名方法和捕获的变量
当你使用:
public Bar CreateBar()
{
    return new Bar(x, () => y);
}
你隐含着意义this.y; 所以在委托方面,它是参考至Foo被包括.因此,Bar(通过委托)的实例保持整个Foo活动(不是垃圾收集)直到Bar可用于收集.
特别是,编译器不需要(在这种情况下)生成一个额外的类来处理捕获的变量; 唯一需要的是Foo实例,因此可以生成一个方法Foo.如果委托涉及局部变量(除了this)之外,这将更复杂.
在序列化方面......好吧,首先我要说的是序列化代表是一个非常糟糕的主意.然而,BinaryFormatter 会走向代表,你可以(理论上)最终得到序列化Bar,序列化Foo和序列化的委托来链接它们 - 但只有你标记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)上的隐藏方法(被调用)的委托.所以它是当前Foo传递给的实例Bar.
| 归档时间: | 
 | 
| 查看次数: | 1342 次 | 
| 最近记录: |