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

.NET 6替换BinaryFormatter实现对象克隆遇空值问题求助

.NET6 替代 BinaryFormatter 实现对象克隆的方案

问题根源

.NET6及后续版本默认禁用BinaryFormatter,核心原因是该组件存在严重安全风险,直接迁移原有代码必然触发报错。你用JsonSerializer克隆返回null,大概率是UserData类缺少公共无参构造函数、属性访问修饰符不符合序列化要求,或是未配置正确的序列化选项。

可靠替代方案

方案1:使用Newtonsoft.Json(JsonConvert)实现克隆

这是兼容性最稳定的方案,只要UserData类结构符合序列化规则就能正常工作,正确实现代码如下:

using Newtonsoft.Json;

public class UserData
{
    // 若存在自定义构造函数,必须显式声明无参构造函数;自动属性场景编译器会默认生成
    public UserData() {}

    // 示例属性,替换为你的实际属性
    public int Id { get; set; }
    public string Username { get; set; }

    public UserData Clone()
    {
        var jsonContent = JsonConvert.SerializeObject(this);
        return JsonConvert.DeserializeObject<UserData>(jsonContent);
    }
}

// 调用方式
var filteredData = records.Clone();

注意事项:

  • 若UserData包含嵌套类,嵌套类也需满足序列化要求(如无参构造函数、公共属性)
  • 私有属性需序列化时,添加[JsonProperty]标记
  • 存在循环引用时,需配置序列化选项:JsonConvert.SerializeObject(this, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore })

方案2:修复System.Text.Json的实现

如果偏好官方的System.Text.Json,需针对性配置解决返回null的问题,代码示例:

using System.Text.Json;

public class UserData
{
    public UserData() {}

    public int Id { get; set; }
    public string Username { get; set; }

    public UserData Clone()
    {
        var serializeOptions = new JsonSerializerOptions
        {
            // 需序列化私有字段时开启
            // IncludeFields = true,
            // 忽略循环引用
            ReferenceHandler = ReferenceHandler.IgnoreCycles,
            // 确保反序列化兼容非无参构造函数场景
            ConstructorHandling = JsonConstructorHandling.Default
        };
        var jsonContent = JsonSerializer.Serialize(this, serializeOptions);
        return JsonSerializer.Deserialize<UserData>(jsonContent, serializeOptions);
    }
}

若仍返回null,排查方向:

  • UserData是否有公共无参构造函数(System.Text.Json默认要求)
  • 属性是否为公共可读写类型
  • 嵌套类型是否未配置序列化规则

方案3:手动实现克隆(性能最优)

对于结构简单的UserData,手动克隆是性能最高的方式,避免序列化/反序列化的额外开销:

public class UserData : ICloneable
{
    public int Id { get; set; }
    public string Username { get; set; }
    // 引用类型属性需注意深克隆,避免浅拷贝导致原对象被修改
    public UserProfile Profile { get; set; }

    public UserData Clone()
    {
        return new UserData
        {
            Id = this.Id,
            Username = this.Username,
            // 引用类型递归实现克隆
            Profile = this.Profile?.Clone()
        };
    }

    object ICloneable.Clone()
    {
        return Clone();
    }
}

// 嵌套类同步实现克隆逻辑
public class UserProfile
{
    public string Email { get; set; }
    public int Age { get; set; }

    public UserProfile Clone()
    {
        return new UserProfile
        {
            Email = this.Email,
            Age = this.Age
        };
    }
}

这种方式完全可控,无序列化开销,适合结构简单的对象场景。

方案4:使用映射库(复杂对象场景)

如果UserData结构复杂,不想手动编写克隆代码,可使用AutoMapper这类映射库:

// 全局初始化一次映射配置
var mapperConfig = new MapperConfiguration(cfg => cfg.CreateMap<UserData, UserData>());
var mapper = mapperConfig.CreateMapper();

public class UserData
{
    // 你的属性...

    public UserData Clone()
    {
        return mapper.Map<UserData>(this);
    }
}

AutoMapper会自动处理属性映射,支持复杂嵌套对象,配置完成后使用成本极低。

总结

  • 追求简单稳定:优先选择Newtonsoft.Json(JsonConvert),兼容性覆盖绝大多数场景
  • 偏好官方库:修复System.Text.Json的序列化配置,确保类符合序列化规则
  • 性能敏感场景:手动实现克隆逻辑
  • 复杂对象场景:使用AutoMapper等映射库减少重复代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:47:20