You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

序列化Reference类时遇c__DisplayClass4未序列化异常求助

解决Reference类序列化时的闭包类未标记可序列化异常

问题背景

我在序列化Reference类对象时遇到了异常,提示DataAnalysis.Reference+<>c__DisplayClass4未标记为可序列化。一开始我没给委托添加[Serializable]特性,加上之后问题依然存在。Cacheable和Operation类已经标记了[Serializable],而且在引入Reference类之前,它们的序列化完全正常。我不清楚c__DisplayClass4是什么含义,因为源码太大没法全部贴出,推测问题集中在Reference类上。

原Reference类代码:

using System;
using System.Reflection;
namespace DataAnalysis {
    /// <summary>
    /// Description of Reference.
    /// </summary>
    [Serializable]
    public class Reference {
        [Serializable]
        public delegate void ReferenceSetter(Operation op, Cacheable c);
        [Serializable]
        public delegate Cacheable ReferenceGetter(Operation op);
        readonly ReferenceGetter refGetter;
        readonly ReferenceSetter refSetter;
        public Reference(ReferenceGetter getter, ReferenceSetter setter) {
            refGetter = getter;
            refSetter = setter;
        }
        public Reference(FieldInfo operationField) {
            refGetter = (op => (Cacheable)operationField.GetValue(op));
            refSetter = ((op, value) => operationField.SetValue(op, value));
        }
        public Cacheable this[Operation op] {
            get {return refGetter(op);}
            set {refSetter(op, value);}
        }
    }
}

问题根因

那个<>c__DisplayClass4是编译器自动生成的闭包类——当你在第二个构造函数里用lambda表达式捕获外部变量operationField时,编译器会创建一个匿名类来持有这个变量,然后让委托引用这个类的实例。这个自动生成的类默认没有标记[Serializable]特性,所以当你序列化Reference对象时,里面的委托会尝试序列化这个闭包类实例,最终抛出异常。哪怕你给委托本身加了[Serializable],也解决不了这个问题,因为问题出在闭包类上。

解决方案

我采用了taffer的第一种方案:避免在委托中直接捕获外部变量,而是把FieldInfo直接存在类的字段里,在索引器的get/set方法中直接使用它。修改后的代码如下:

public class Reference {
    public delegate void ReferenceSetter(Operation op, Cacheable c);
    public delegate Cacheable ReferenceGetter(Operation op);
    readonly FieldInfo opField;
    readonly ReferenceGetter refGetter;
    readonly ReferenceSetter refSetter;
    public Reference(ReferenceGetter getter, ReferenceSetter setter) {
        refGetter = getter;
        refSetter = setter;
    }
    public Reference(FieldInfo operationField) {
        opField = operationField;
    }
    public Cacheable this[Operation op] {
        get { if (opField != null) return (Cacheable)opField.GetValue(op); else return refGetter(op); }
        set { if (opField != null) opField.SetValue(op, value); else refSetter(op, value); }
    }
}

目前代码还没做优化,最终可能会改成抽象Reference类加两个实现类的方案,但核心原理已经明确:绕过闭包类,直接持有需要的字段信息,不在委托中捕获外部变量,从而避免序列化编译器生成的未标记可序列化的闭包类。

内容的提问来源于stack exchange,提问作者oliver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:05:43