DataContractSerializer的问题 - 如何正确序列化从List <t>派生的对象?</t>

时间:2009-12-01 20:05:48

标签: .net datacontractserializer

请注意以下示例代码:

namespace A
{
  [Serializable]
  internal class ComplexObject<T> : List<T>, IEquatable<ComplexObject<T>>
    where T : IEquatable<T>
  {
    private T m_state;

    internal T State
    {
      get { return m_state; }
      set { m_state = value; }
    }

    public bool Equals(ComplexObject<T> other)
    {
      // Implementation is omitted to save space.
    }
  }

  public static class Program
  {
    public static void Main()
    {
      var obj = new ComplexObject<int>();
      obj.State = 100;
      var stream = new MemoryStream();
      var serializer = new DataContractSerializer(obj.GetType());
      serializer.WriteObject(stream, obj);
      stream.Flush();
      stream.Seek(0, SeekOrigin.Begin);
      var copy = (ComplexObject<int>)serializer.ReadObject(stream);
      Debug.Assert(obj.Equals(copy));
    }
  }
}

请注意,ComplexObject<T>来自List<T>

无论如何,最后一个断言失败了。 将[Serializable]替换为[CollectionDataContract]并将[DataMember]附加到m_state会产生相同的否定结果。

好像DataContractSerializer注意到该类是一个集合,并选择忽略其他状态。

请告知任何人如何解决这个问题:

  • 我想尽可能少地对ComplexObject<T>进行更改
  • 由于与此问题无关的原因,我被DataContractSerializer困住了

提前多多感谢。

修改

public bool Equals(ComplexObject<T> other)
{
  if (!m_state.Equals(other.m_state) || Count != other.Count)
  {
    return false;
  }

  bool result = true;
  for (int i = 0; i < Count && (result = this[i].Equals(other[i])); ++i)
  {
  }
  return result;
}

3 个答案:

答案 0 :(得分:2)

要正确序列化List结构,您必须使用 CollectionDataContract 属性,如下所示:

 [CollectionDataContract]
 [Serializable]
 internal class ComplexObject<T> : List<T>, IEquatable<ComplexObject<T>>
    where T : IEquatable<T> 

但是,CollectionDataContract不允许序列化其他DataMembers。解决方法是避免从列表继承,而是使其成为成员变量,并可选择实现ICollection,如下所示:

[DataContract]
[Serializable]
internal class ComplexObject<T> : ICollection<T>, IEquatable<ComplexObject<T>>
  where T : IEquatable<T> 
{
    private T m_state;

    [DataMember]
    public T State
    {
        get { return m_state; }
        set { m_state = value; }
    }

    private List<T> m_List = new List<T>();

    [DataMember]
    public List<T> List
    {
        get { return m_List; }
        set { m_List = value; }
    }

    public bool Equals(ComplexObject<T> other)
    {
        if (!other.State.Equals(State))
            return false;

        if (other.List.Count != List.Count)
            return false;

        for (int i = 0; i < other.List.Count;i++)
        {
            if (!other.List[i].Equals(List[i]))
                return false;
        }

        return true;
    }

    // ICollection members left out to save space

    // helper methods to wrap around the List to decrease the amount
    // of refactoring work you would have to do
    public void Add(T item)
    {
        List.Add(item);
    }

    public bool Remove(T item)
    {
        return List.Remove(item);
    }

    public T this[int index]
    {
        get { return List[index]; }
    }
}

答案 1 :(得分:1)

问题是当你试图返回一个对象的数组时 - 至少它对我而言。

我发现我需要创建一个对象类类型的List,将该列表添加到DataContractSerrializer(typeof(mylist));

由此;

List<LinqtoSQLTableClass> mylist = new List<LinqtoSQLTableClass>();
DataContractSerializer(mylist.GetType());
StringBuilder sb = new StringBuilder();

var query = linqtosql blah blah

XmlWriter writer = XmlWriter.Create(sb);
            dcs.WriteObject(writer, query);        
            writer.Close();

答案 2 :(得分:-1)

以下是我用于克隆或序列化对象的一些代码。我很想知道你是否有同样的问题。此代码只返回一个Object类型,但您可以将结果强制转换为对象类型。

var serializer = new System.Runtime.Serialization.DataContractSerializer(GetType());
using (var ms = new System.IO.MemoryStream())
{
   serializer.WriteObject(ms, this);
   ms.Position = 0;
   return serializer.ReadObject(ms);
}