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

跨平台移植下C#反序列化:客户端跳过特定字段组的解决方案

解决C#跨平台序列化中编辑器专属字段的兼容问题

这个问题我之前在跨平台项目里也碰到过,核心就是要让序列化逻辑根据运行环境(编辑器/客户端)动态调整——既要让编辑器能完整读写所有字段,又要让客户端跳过那些依赖Windows专属组件的字段,避免反序列化时抛出类型找不到的异常。下面给你几个实用的解决方案:

方案一:条件编译+序列化属性标记

这是最直接的方式,利用C#的条件编译指令,让编辑器和客户端对同一个字段采用不同的序列化规则。

首先,你需要给编辑器项目添加编译符号(比如EDITOR):在编辑器项目的属性→生成→条件编译符号里输入EDITOR;客户端项目则不添加这个符号。

然后修改你的_ev结构体:

[Serializable]
public struct _ev {
    public int evntID;
    public int PositionX;
    public int PosotionY;
    public List<string> ComCode;
    public byte[] EventGraphics;

#if EDITOR
    // 编辑器环境下,该字段正常参与序列化
    public List<Graphics.Node> NodeGraph; //Editor only information
#else
    // 客户端环境下,标记为不序列化,避免反序列化报错
    [NonSerialized]
    public List<Graphics.Node> NodeGraph; //Editor only information
#endif

    public List<pages> Pages;
    public List<EventItem> Event;
}

这样一来,编辑器编译时会把NodeGraph当作普通可序列化字段处理;客户端编译时,这个字段会被标记为[NonSerialized],序列化和反序列化过程都会自动跳过它,也就不会因为找不到Graphics.Node类型而抛出异常了。

方案二:自定义序列化逻辑(实现ISerializable接口)

如果需要更精细的控制(比如字段较多,或者要处理复杂的序列化场景),可以让结构体实现ISerializable接口,手动控制哪些字段参与序列化/反序列化。

using System.Runtime.Serialization;

[Serializable]
public struct _ev : ISerializable {
    public int evntID;
    public int PositionX;
    public int PosotionY;
    public List<string> ComCode;
    public byte[] EventGraphics;
    public List<Graphics.Node> NodeGraph; //Editor only information
    public List<pages> Pages;
    public List<EventItem> Event;

    // 常规构造函数(根据你的需求初始化字段)
    public _ev(int evntId, int posX, int posY, /* 其他参数 */) {
        evntID = evntId;
        PositionX = posX;
        PosotionY = posY;
        ComCode = new List<string>();
        EventGraphics = Array.Empty<byte>();
        NodeGraph = new List<Graphics.Node>();
        Pages = new List<pages>();
        Event = new List<EventItem>();
    }

    // 反序列化构造函数(必须是private)
    private _ev(SerializationInfo info, StreamingContext context) {
        // 读取所有客户端和编辑器共用的字段
        evntID = info.GetInt32(nameof(evntID));
        PositionX = info.GetInt32(nameof(PositionX));
        PosotionY = info.GetInt32(nameof(PosotionY));
        ComCode = (List<string>)info.GetValue(nameof(ComCode), typeof(List<string>));
        EventGraphics = (byte[])info.GetValue(nameof(EventGraphics), typeof(byte[]));
        Pages = (List<pages>)info.GetValue(nameof(Pages), typeof(List<pages>));
        Event = (List<EventItem>)info.GetValue(nameof(Event), typeof(List<EventItem>));

        // 只有编辑器环境下才读取NodeGraph字段
#if EDITOR
        NodeGraph = (List<Graphics.Node>)info.GetValue(nameof(NodeGraph), typeof(List<Graphics.Node>));
#else
        NodeGraph = null;
#endif
    }

    // 序列化方法
    public void GetObjectData(SerializationInfo info, StreamingContext context) {
        // 写入所有共用字段
        info.AddValue(nameof(evntID), evntID);
        info.AddValue(nameof(PositionX), PositionX);
        info.AddValue(nameof(PosotionY), PosotionY);
        info.AddValue(nameof(ComCode), ComCode);
        info.AddValue(nameof(EventGraphics), EventGraphics);
        info.AddValue(nameof(Pages), Pages);
        info.AddValue(nameof(Event), Event);

        // 只有编辑器环境下才写入NodeGraph字段
#if EDITOR
        info.AddValue(nameof(NodeGraph), NodeGraph);
#endif
    }
}

这种方式的优势是完全可控,你可以根据不同的StreamingContext或者环境变量做更复杂的判断,适合字段多、逻辑复杂的场景。

方案三:使用DataContractSerializer(适合WCF/跨语言场景)

如果你的项目用的是DataContractSerializer而非BinaryFormatter,可以结合[DataMember]属性和条件编译来实现:

using System.Runtime.Serialization;

[DataContract]
public struct _ev {
    [DataMember]
    public int evntID;
    [DataMember]
    public int PositionX;
    [DataMember]
    public int PosotionY;
    [DataMember]
    public List<string> ComCode;
    [DataMember]
    public byte[] EventGraphics;

#if EDITOR
    [DataMember] // 编辑器环境下标记为可序列化字段
#endif
    public List<Graphics.Node> NodeGraph; //Editor only information

    [DataMember]
    public List<pages> Pages;
    [DataMember]
    public List<EventItem> Event;
}

只有当EDITOR符号被定义时,NodeGraph才会被标记为[DataMember],参与序列化和反序列化;客户端环境下这个字段会被自动忽略。

注意事项

  1. 确保编辑器和客户端的编译符号设置正确,这是所有方案生效的前提;
  2. 如果你用的是BinaryFormatter,注意结构体作为值类型的序列化特性——默认情况下所有字段都会被序列化,必须通过[NonSerialized]或自定义逻辑排除;
  3. 如果Graphics.Node本身不是可序列化类型,编辑器端也需要确保它实现了[Serializable]接口或ISerializable接口,否则编辑器序列化时也会报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:09:25