假设我有以下简单类:
[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',名称空间''。
所以,我的问题变成了:
eString
或任何IEnumerable<char>
的序列化并始终按字符串序列化?谢谢!
更新#1:
所以,我从我的eString中删除了IEnumerable<char>
接口,然后离开了IEnumerable<char>.GetEnumerator()
方法,这允许我的字符串在foreach循环中用作IEnumerable<char>
,但序列化为串。 #WIN
另外,感谢dbc,使用XML Deserializer(而不是DataContract Serializer)更新原始帖子并进行反序列化。
答案 0 :(得分:3)
回答你的问题:
您可能不应该使用自定义字符串解决方案重新发明轮子。无论如何,如果你想对(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);
}
}
CustomString的序列化现在产生<string-wrapper>Testing</string-wrapper>
。我将在本文末尾发布一些测试代码。
现在......忘掉刚才告诉你的事。除非您有非常具体的格式要求,否则不将实现您自己的字符串版本。内置的格式化程序知道更多的格式化技巧(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);
}
}
}