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

发布于 2024-08-13 07:00:26 字数 1719 浏览 7 评论 0原文

请观察以下示例代码:

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 派生自 List

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

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

请建议任何人如何解决此问题,因为:

  • 我想对 ComplexObject 进行尽可能少的更改,
  • 由于与此无关的原因,我陷入了 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;
}

Observe the following sample code:

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));
    }
  }
}

Note that ComplexObject<T> derives from List<T>.

Anyway, the last assertion fails.
Replacing [Serializable] with [CollectionDataContract] and attaching [DataMember] to m_state yields the same negative result.

It is as though the DataContractSerializer notices that the class is a collection and chooses to ignore its other state.

Please advice anyone how to solve this issue given that:

  • I would like to make as few changes to ComplexObject<T> as possible
  • I am stuck with DataContractSerializer for reasons irrelevant for this question

Thanks a lot in advance.

EDIT:

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遗失的美好 2024-08-20 07:00:26

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

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

但是,CollectionDataContract 不允许序列化其他 DataMember。解决方法是避免从列表继承,而是将其设为成员变量,并可选择实现 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]; }
    }
}

To correctly serialize a List structure, you have to use the CollectionDataContract attribute like so:

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

However, the CollectionDataContract doesn't allow for additional DataMembers to be serialized. The workaround would be to avoid inheriting from the list, but make it a member variable instead and optionally implement the ICollection, like so:

[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]; }
    }
}
意犹 2024-08-20 07:00:26

问题是当你试图返回对象的数组时 - 至少对我来说是这样。

我发现我需要创建一个对象类类型的列表,将该列表添加到 DataContractSerializer(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();

The problem is when you are trying to return an array of your object - at least it was for me.

I figure out that I needed to create a List of the type of my object class, add that list to the DataContractSerrializer(typeof(mylist));

thus;

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();
怎言笑 2024-08-20 07:00:26

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

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);
}

Here is some code I have for cloning or serializing an object. I would be curious to see if you have the same issues with this. This code simply returns an Object type, but you can cast the result to your object type.

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文