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

时间:2008-10-14 16:50:32

标签: c# clipboard deep-copy idataobject

我正在尝试在C#中创建一个剪贴板堆栈。剪贴板数据存储在System.Windows.Forms.DataObject个对象中。我想将每个剪贴板条目(IDataObject)直接存储在通用列表中。由于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);
}

3 个答案:

答案 0 :(得分:3)

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

    public static class GhettoSerializer
    {
            // you could make this a factory method if your type
            // has a constructor that appeals to you (i.e. default 
            // parameterless constructor)
            public static void Initialize<T>(T instance, IDictionary<string, object> 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<object,object,object[]>(property.SetValue), 
                                            kvp.Value
                                    }
                    );

                    foreach (var match in matches)
                            match.Set(instance, match.Value, null);
            }
            public static IDictionary<string, object> Serialize<T>(T instance)
            {
                    var props = typeof(T).GetProperties();

                    var ret = new Dictionary<string, object>();

                    foreach (var property in props)
                    {
                            if (!property.CanWrite || !property.CanRead)
                                    continue;
                            ret.Add(property.Name, property.GetValue(instance, null));
                    }

                    return ret;
            }
    }

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

将我的答案复制到:difference between DataContract attribute and Serializable attribute in .net

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

结束
  

&#34; ...或者可能是另一种创建深层克隆的方式?&#34;

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

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

private void InspectRecursively(object input,
    Dictionary<object, bool> processedObjects)
{
  if ((input != null) && !processedObjects.ContainsKey(input))
  {
    processedObjects.Add(input, true);

    List<FieldInfo> 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)

之类的内容设置每个字段

但是,此实现不支持已注册的事件处理程序,反序列化也支持_ un _。此外,层次结构中的每个对象都将被破坏,如果它的类别为&#39;构造函数需要初始化任何东西,但设置所有字段。最后一点仅适用于序列化,如果该类具有相应的实现,例如标记为[OnDeserialized]的方法,实现ISerializable,....