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

从Windows窗体控件复制粘贴到WPF控件时出现序列化错误(.NET5迁移后)

报错根本原因

程序集“System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e”中的类型“System.RuntimeType”未标记为可序列化。

该报错由ClipboardDescriptor类中两个不符合.NET 5+序列化规则的成员触发:

  • System.Type类型的ObjType字段:.NET Framework中RuntimeType(Type的实际实现类)默认标记了可序列化,但.NET 5+重构了核心库实现,System.Private.CoreLib下的RuntimeType不再支持二进制序列化
  • System.Windows.Forms.TreeNode类型的BaseTreeNode字段:WinForms控件本身的序列化逻辑不稳定,不适合跨UI框架(WinForms到WPF)传递

修复方案

方案1:替换不可序列化成员(推荐)

直接把不可序列化的字段替换为纯数据类型,避免框架兼容性问题:

  1. 将System.Type ObjType替换为字符串类型的类型全名字段,需要使用类型时再通过反射动态加载
  2. 将TreeNode BaseTreeNode替换为节点的唯一标识(如节点ID、名称、路径等),拖拽完成后在WPF端根据标识查找对应控件对象

修改后的类示例:

using System;

namespace Support.Classes
{
    /// <summary>
    /// ClipboardDescriptor的摘要说明
    /// </summary>
    [Serializable]
    public class ClipboardDescriptor
    {
        private Guid id;
        private Guid parentDocumentID;
        // 替换Type为类型全名字符串
        private string objTypeFullName;
        // 替换TreeNode为节点唯一标识
        private string treeNodeUniqueKey;
        private string objname;

        public ClipboardDescriptor()
        {
        }

        public Guid ParentDocumentID
        {
            get { return parentDocumentID; }
            set { parentDocumentID = value; }
        }

        public Guid ID
        {
            get { return id; }
            set { id = value; }
        }

        public string ObjTypeFullName
        {
            get { return objTypeFullName; }
            set { objTypeFullName = value; }
        }

        // 辅助方法,需要使用Type时动态获取
        public Type GetObjType()
        {
            return string.IsNullOrEmpty(objTypeFullName) ? null : Type.GetType(objTypeFullName);
        }

        public string ObjName
        {
            get { return objname; }
            set { objname = value; }
        }

        public string TreeNodeUniqueKey
        {
            get { return treeNodeUniqueKey; }
            set { treeNodeUniqueKey = value; }
        }
    }
}

修改后原有拖拽代码var tClip = e.Data.GetDataPresent(typeof(ClipboardDescriptor));可正常运行。

方案2:自定义序列化逻辑

如果必须保留原有类的字段定义,可以实现ISerializable接口手动控制序列化过程:

using System;
using System.Runtime.Serialization;
using System.Windows.Forms;

namespace Support.Classes
{
    [Serializable]
    public class ClipboardDescriptor : ISerializable
    {
        private Guid id;
        private Guid parentDocumentID;
        private System.Type objtype;
        private TreeNode baseTreeNode;
        private string objname;

        public ClipboardDescriptor()
        {
            baseTreeNode = null;
        }

        // 反序列化构造函数
        protected ClipboardDescriptor(SerializationInfo info, StreamingContext context)
        {
            id = (Guid)info.GetValue(nameof(ID), typeof(Guid));
            parentDocumentID = (Guid)info.GetValue(nameof(ParentDocumentID), typeof(Guid));
            objname = info.GetString(nameof(ObjName));
            // 从序列化字符串中还原Type
            var typeName = info.GetString(nameof(objtype));
            objtype = string.IsNullOrEmpty(typeName) ? null : Type.GetType(typeName);
            // TreeNode控件不序列化,反序列化后在目标端重新查找赋值
        }

        // 自定义序列化逻辑
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue(nameof(ID), id);
            info.AddValue(nameof(ParentDocumentID), parentDocumentID);
            info.AddValue(nameof(ObjName), objname);
            // Type转为字符串存储
            info.AddValue(nameof(objtype), objtype?.AssemblyQualifiedName);
            // 跳过TreeNode的序列化
        }

        public Guid ParentDocumentID
        {
            get { return parentDocumentID; }
            set { parentDocumentID = value; }
        }

        public Guid ID
        {
            get { return id; }
            set { id = value; }
        }

        public System.Type ObjType
        {
            get { return objtype; }
            set { objtype = value; }
        }

        public string ObjName
        {
            get { return objname; }
            set { objname = value; }
        }

        public TreeNode BaseTreeNode
        {
            get { return baseTreeNode; }
            set { baseTreeNode = value; }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 02:36:03