如何执行未标记为可序列化的对象的深层副本(在C#中)?

我试图在C#中创建一个剪贴板堆栈。 剪贴板数据存储在System.Windows.Forms.DataObject对象中。 我想将每个剪贴板条目( IDataObject )直接存储在Generic列表中。 由于Bitmaps(似乎是)存储的方式我认为我需要先将深拷贝执行才能将其添加到列表中。

我尝试使用二进制序列化(见下文)来创建深层副本,但由于System.Windows.Forms.DataObject未标记为可序列化,因此序列化步骤失败。 有任何想法吗?

 public IDataObject GetClipboardData() { MemoryStream memoryStream = new MemoryStream(); BinaryFormatter binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(memoryStream, Clipboard.GetDataObject()); memoryStream.Position = 0; return (IDataObject) binaryFormatter.Deserialize(memoryStream); } 

查找Serializable的底座,找到有关序列化助手的内容。 您可以将位图包装在您自己的序列化代码中,并与.net框架集成。

我在下面编写了另一个问题的代码,在这种情况下它可能会对你有用:

  public static class GhettoSerializer { // you could make this a factory method if your type // has a constructor that appeals to you (ie default // parameterless constructor) public static void Initialize(T instance, IDictionary values) { var props = typeof(T).GetProperties(); // my approach does nothing to handle rare properties with array indexers var matches = props.Join( values, pi => pi.Name, kvp => kvp.Key, (property, kvp) => new { Set = new Action(property.SetValue), kvp.Value } ); foreach (var match in matches) match.Set(instance, match.Value, null); } public static IDictionary Serialize(T instance) { var props = typeof(T).GetProperties(); var ret = new Dictionary(); foreach (var property in props) { if (!property.CanWrite || !property.CanRead) continue; ret.Add(property.Name, property.GetValue(instance, null)); } return ret; } } 

但是我不认为这将是你问题的最终解决方案,虽然它可能会给你一个开始的地方。

我的答案的副本: .net中的DataContract属性和Serializable属性之间的区别

我的回答比这里好得多,尽管上面的问题以下结尾:

“……或者可能是另一种创建深层克隆的方式?”

我曾经通过Reflection对对象结构进行了一些检查,以找到反序列化所需的所有程序集,并将它们串行化以进行自举。

通过一些工作,可以构建类似的深度复制方法。 基本上你需要一个递归方法,沿着Dictionary来检测循环引用。 在方法内部,您将检查所有字段,如下所示:

 private void InspectRecursively(object input, Dictionary processedObjects) { if ((input != null) && !processedObjects.ContainsKey(input)) { processedObjects.Add(input, true); List fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ); foreach (FieldInfo field in fields) { object nextInput = field.GetValue(input); if (nextInput is System.Collections.IEnumerable) { System.Collections.IEnumerator enumerator = (nextInput as System.Collections.IEnumerable).GetEnumerator(); while (enumerator.MoveNext()) { InspectRecursively(enumerator.Current, processedObjects); } } else { InspectRecursively(nextInput, processedObjects); } } } } 

要使其工作,您需要添加一个输出对象和System.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)东西,以创建每个字段值的最浅的副本(即使没有复制引用)。 最后,您可以使用field.SetValue(input, output)等设置每个字段

但是,此实现不支持已注册的事件处理程序,这也是反序列化所支持的事件。 此外,如果其类的构造函数需要初始化除了设置所有字段之外的任何内容,那么层次结构中的每个对象都将被破坏。 最后一点仅适用于序列化,如果类具有相应的实现,例如标记为[OnDeserialized]方法,则实现ISerializable ,….