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

.NET 7中反序列化含MemoryStream的Serializable类报错排查

问题分析与解决方案

问题原因

.NET Framework 中 System.IO.MemoryStream 类型标记了 [Serializable] 特性,因此可以被 BinaryFormatter 正常序列化/反序列化。但从 .NET Core(包括 .NET 7)开始,MemoryStream 移除了该特性,导致用旧 .NET Framework 序列化的文件在 .NET 7 中反序列化时,触发 SerializationException,提示该类型未标记可序列化。

必要前提配置

由于 BinaryFormatter 在 .NET 5+ 中被标记为不安全且默认禁用,首先需要在项目文件(.csproj)中启用兼容性开关,否则无法使用该组件:

<PropertyGroup>
    <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

解决方案

方案1:使用序列化代理(无需修改原Quest类)

通过实现 ISerializationSurrogate 为 MemoryStream 自定义序列化/反序列化逻辑,让 BinaryFormatter 能识别并处理该类型。

代码实现

using System.Runtime.Serialization;
using System.IO;

public class MemoryStreamSurrogate : ISerializationSurrogate
{
    // 处理序列化逻辑(若需要重新序列化新文件时生效)
    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var ms = (MemoryStream)obj;
        info.AddValue("Data", ms.ToArray());
    }

    // 处理反序列化逻辑(核心:从旧文件的序列化数据重建MemoryStream)
    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        byte[] data = (byte[])info.GetValue("Data", typeof(byte[]));
        return new MemoryStream(data);
    }
}

// 反序列化时的使用方式
var formatter = new BinaryFormatter();
var surrogateSelector = new SurrogateSelector();
// 为MemoryStream类型注册代理
surrogateSelector.AddSurrogate(
    typeof(MemoryStream),
    new StreamingContext(StreamingContextStates.All),
    new MemoryStreamSurrogate()
);
formatter.SurrogateSelector = surrogateSelector;

using (var fileStream = File.OpenRead("your-quest-file.dat"))
{
    var quest = (Quest)formatter.Deserialize(fileStream);
}

方案2:修改Quest类(替换MemoryStream为byte[])

若允许修改原 Quest 类,可以将 MemoryStream 属性替换为 byte[] 存储,通过序列化回调方法实现自动转换,既兼容旧文件,也能适配新框架。

代码实现

using System.Runtime.Serialization;
using System.IO;

[Serializable]
public class Quest
{
    // 存储序列化的流数据(对应旧文件中MemoryStream的内容)
    private byte[] _streamData;

    // 非序列化的MemoryStream实例,仅在运行时使用
    [NonSerialized]
    private MemoryStream _memoryStream;

    // 对外暴露的MemoryStream属性
    public MemoryStream QuestStream
    {
        get
        {
            if (_memoryStream == null && _streamData != null)
            {
                _memoryStream = new MemoryStream(_streamData);
            }
            return _memoryStream;
        }
        set
        {
            _memoryStream = value;
            _streamData = value?.ToArray();
        }
    }

    // 反序列化完成后重建MemoryStream
    [OnDeserialized]
    private void OnDeserialized(StreamingContext context)
    {
        if (_streamData != null)
        {
            _memoryStream = new MemoryStream(_streamData);
        }
    }

    // 序列化前将MemoryStream转换为byte[]
    [OnSerialized]
    private void OnSerialized(StreamingContext context)
    {
        if (_memoryStream != null)
        {
            _streamData = _memoryStream.ToArray();
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:27:39