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

C#中如何无引用复制基类类型声明的派生类实例?

解决基类引用下派生类实例的通用克隆问题

你的核心问题在于反序列化时没有指定对象的实际派生类型,导致Json.NET只能创建基类ModelBase的实例,丢失了派生类的属性。这里有个直接且安全的解决方案,利用model.GetType()获取实际类型,再调用Json.NET的重载方法反序列化:

修改后的CloneModel方法

protected ModelBase CloneModel(ModelBase model)
{
    if (model == null)
        return null;
        
    // 获取对象的实际派生类型(比如ModelUser)
    Type actualType = model.GetType();
    string json = JsonConvert.SerializeObject(model);
    
    // 使用接受Type参数的反序列化重载,创建正确的派生类实例
    return (ModelBase)JsonConvert.DeserializeObject(json, actualType);
}

为什么之前的方法失败?

  • 第一种尝试JsonConvert.DeserializeObject<ModelBase>(json):泛型参数指定了基类,Json.NET只会解析ModelBase中定义的属性(也就是Status),完全忽略派生类的额外属性,最终得到的是纯ModelBase实例。
  • 第二种尝试JsonConvert.DeserializeObject<object>(json):当目标类型是object时,Json.NET默认会将JSON解析为JObject(它的动态JSON对象类型),而不是你期望的实体类实例,所以强转ModelBase会出错。

验证效果

在你的派生窗体FormMVBaseUser中,现在_originalModel的实际类型是ModelUser,可以安全访问派生类属性(建议先做类型检查避免异常):

private void button1_Click(object sender, EventArgs e)
{
    if (_originalModel is ModelUser originalUser && model is ModelUser currentUser)
    {
        if (originalUser.UserFirst != currentUser.UserFirst)
        {
            // 执行相关操作
        }
    }
}

可选方案:利用TypeNameHandling(需注意安全)

如果你希望Json.NET自动处理类型信息,可以在序列化和反序列化时启用TypeNameHandling.Auto,这样JSON中会包含类型标识,反序列化时自动还原为正确的派生类:

protected ModelBase CloneModel(ModelBase model)
{
    if (model == null)
        return null;
        
    var settings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Auto
    };
    
    string json = JsonConvert.SerializeObject(model, settings);
    return (ModelBase)JsonConvert.DeserializeObject(json, settings);
}

⚠️ 注意:如果你的程序会反序列化来自不可信来源的JSON,不建议使用TypeNameHandling,因为存在反序列化攻击的风险。直接使用GetType()的方法更安全,也更适配你的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 10:03:13