如何将IEnumerable <char>序列化为字符串&amp;令人困惑的反序列化错误

时间:2015-07-21 18:24:59

标签: c# xml serialization

假设我有以下简单类:

[XmlRoot]
[XmlType("string")]
public partial class eString : IEnumerable<char>
{
    string AsString {get;set;}
    public IEnumerator<char> GetEnumerator()
    {
        return this.AsString.ToCharArray().ToList().GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.AsString.ToCharArray().GetEnumerator();
    }
    public void Add(char character)
    {
        this.AsString += character;
    }
}

还是namedValue类:

[XmlRoot]
public partial class eNamedValue: KeyValuePair<eString,object>
{...}

最后,

[XmlRoot]
public partial class eList<T>: List<eNamedValue>
{...}

现在,我使用以下XML序列化程序序列化 eList 或任何继承自eList的类:

    public static XDocument Serialize<T>(this T obj) where T: new()
    {
        Type tt = obj.GetType();
        XmlSerializer xsSubmit = new XmlSerializer(tt);
        StringWriter sww = new StringWriter();
        XmlWriter writer = XmlWriter.Create(sww);
        xsSubmit.Serialize(writer, obj);
        return XDocument.Parse(sww.ToString());
    }

序列化工作 - 但是我的eString被序列化为一个字符数组,所以我得到的是单个字符值,而不是获得“字符串”:

<eNamedList>
  <Key>99</Key>
  <Key>111</Key>
  <Key>100</Key>
  <Key>101</Key>...

此外,关于反序列化(已解决,请参阅下面的更新#1):

public static T Deserialize<T>(this XDocument xml) where T: new()
    {
        var serializer = new XmlSerializer(typeof(T));
        T result;

        using (TextReader reader = new StringReader(xml.ToString()))
        {
            result = (T)serializer.Deserialize(reader);
        }
        return result;
    }

我收到以下错误:

  

System.Runtime.Serialization.SerializationException:第1行位置错误111.期望来自命名空间“http://schemas.datacontract.org/2004/07/Epic”的元素'eNamedList'。遇到名为'eNamedList'的'Element',名称空间''。

所以,我的问题变成了:

  1. 如何控制eString或任何IEnumerable<char>的序列化并始终按字符串序列化?
  2. 为什么,当元素名称匹配时,我是否在反序列化时失败? (我只是缺少名称空间声明吗?)
  3. 谢谢!

    更新#1: 所以,我从我的eString中删除了IEnumerable<char>接口,然后离开了IEnumerable<char>.GetEnumerator()方法,这允许我的字符串在foreach循环中用作IEnumerable<char>,但序列化为串。 #WIN

    另外,感谢dbc,使用XML Deserializer(而不是DataContract Serializer)更新原始帖子并进行反序列化。

1 个答案:

答案 0 :(得分:3)

回答你的问题:

  1. 您可能不应该使用自定义字符串解决方案重新发明轮子。无论如何,如果你想对(de-)序列化进行(疯狂的)高级控制,你可以实现IXmlSerializable并自己做同样的事情。

    [XmlRoot("string-wrapper")]
    public class CustomString : IXmlSerializable
    {
        public string Value { get; set; }
    
        public XmlSchema GetSchema()
        {
            return null; // GetSchema should not be used.
        }
    
        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();
            bool isEmpty = reader.IsEmptyElement;
    
            reader.ReadStartElement();
            if (!isEmpty)
            {
                Value = reader.ReadString();
                reader.ReadEndElement();
            }
        }
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteString(Value);
        }
    }
    
  2. CustomString的序列化现在产生<string-wrapper>Testing</string-wrapper>。我将在本文末尾发布一些测试代码。

    1. 您的反序列化可能会被破坏,因为XmlSerializer并不知道您标记为可序列化的IEnumerable实际上应该被视为字符串。
    2. 现在......忘掉刚才告诉你的事。除非您有非常具体的格式要求,否则将实现您自己的字符串版本。内置的格式化程序知道更多的格式化技巧(http://www.w3.org/TR/xmlschema-2/#built-in-datatypes),所以你应该让它做它的工作。

      序列化类是属性的来源,但我建议你切换到WFC数据合同,这可能听起来很可怕,但实际上为更少的代码提供了更多。同样,我不确定你要完成什么,但相信我,你不想养成手写XML的习惯。

      如果你想要它,你可能会喜欢动态对象和ExpandoObject(http://www.codeproject.com/Tips/227139/Converting-XML-to-an-dynamic-object-using-ExpandoO)。这些消除了所有类型,允许您动态创建字典,数组,命名属性等等!

      最后,简单的泛型!反序列化泛型类不是一项简单的任务。此外,你可能不需要。如果您需要自己的集合,请尝试使用System.Collections.ObjectModel命名空间。您不必担心维护列表和实现接口,只是您实际存储的内容:

      class DictionaryOfStringsAndObjects : KeyedCollection<string, object {...}
      class CollectionOfStrings : Collection<string> {...}
      

      此外,尽量避免使用ORM或大型遗留类强制部分类。除非你做了,否则你不应该实际使用它们。

      所有最好的,以及没有XML的未来!

      public class CustomSerializer
      {
          public static void Test()
          {
              var obj = new CustomString {Value = "Random string!"};
              var serializer = new CustomSerializer();
              var xml = serializer.Serialize(obj);
              Console.WriteLine(xml);
      
              var obj2 = serializer.Deserialize<CustomString>(xml);
          }
      
          public string Serialize(object obj)
          {
              var serializer = new XmlSerializer(obj.GetType());
              using (var io = new StringWriter())
              {
                  serializer.Serialize(io, obj);
                  return io.ToString();
              }
          }
      
          public T Deserialize<T>(string xml)
          {
              var serializer = new XmlSerializer(typeof (T));
              using (var io = new StringReader(xml))
              {
                  return (T)serializer.Deserialize(io);
              }
          }
      }