通过 DataContract 序列化为 XML:自定义输出?
我有一个自定义 Fraction 类,我在整个项目中都使用它。它很简单,它由一个构造函数组成,接受两个 int 并存储它们。我想使用 DataContractSerializer 来序列化项目中使用的对象,其中一些对象包含分数作为字段。理想情况下,我希望能够像这样序列化此类对象:
<Object>
...
<Frac>1/2</Frac> // "1/2" would get converted back into a Fraction on deserialization.
...
</Object>
与此相反:
<Object>
...
<Frac>
<Numerator>1</Numerator>
<Denominator>2</Denominator>
</Frac>
...
</Object>
有没有办法使用 DataContracts 来做到这一点?
我想这样做,因为我计划制作XML 文件用户可编辑(我使用它们作为音乐游戏的输入,它们本质上充当笔记图表),并且希望为最终用户保留尽可能简洁的符号,因此他们不需要处理尽可能多的文字墙。
编辑:我还应该注意,我目前的 Fraction 类是不可变的(所有字段都是只读
),因此无法更改现有 Fraction 的状态有可能。不过,返回一个新的 Fraction 对象就可以了。
I have a custom Fraction class, which I'm using throughout my whole project. It's simple, it consists of a single constructor, accepts two ints and stores them. I'd like to use the DataContractSerializer to serialize my objects used in my project, some of which include Fractions as fields. Ideally, I'd like to be able to serialize such objects like this:
<Object>
...
<Frac>1/2</Frac> // "1/2" would get converted back into a Fraction on deserialization.
...
</Object>
As opposed to this:
<Object>
...
<Frac>
<Numerator>1</Numerator>
<Denominator>2</Denominator>
</Frac>
...
</Object>
Is there any way to do this using DataContracts?
I'd like to do this because I plan on making the XML files user-editable (I'm using them as input for a music game, and they act as notecharts, essentially), and want to keep the notation as terse as possible for the end user, so they won't need to deal with as many walls of text.
EDIT: I should also note that I currently have my Fraction class as immutable (all fields are readonly
), so being able to change the state of an existing Fraction wouldn't be possible. Returning a new Fraction object would be OK, though.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(5)
DataContractSerializer
将使用自定义 IXmlSerialized
如果它是代替 提供的DataContractAttribute
。这将允许您以任何需要的方式自定义 XML 格式...但是您必须为您的类手动编写序列化和反序列化过程的代码。
public class Fraction: IXmlSerializable
{
private Fraction()
{
}
public Fraction(int numerator, int denominator)
{
this.Numerator = numerator;
this.Denominator = denominator;
}
public int Numerator { get; private set; }
public int Denominator { get; private set; }
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
var content = reader.ReadInnerXml();
var parts = content.Split('/');
Numerator = int.Parse(parts[0]);
Denominator = int.Parse(parts[1]);
}
public void WriteXml(XmlWriter writer)
{
writer.WriteRaw(this.ToString());
}
public override string ToString()
{
return string.Format("{0}/{1}", Numerator, Denominator);
}
}
[DataContract(Name = "Object", Namespace="")]
public class MyObject
{
[DataMember]
public Fraction Frac { get; set; }
}
class Program
{
static void Main(string[] args)
{
var myobject = new MyObject
{
Frac = new Fraction(1, 2)
};
var dcs = new DataContractSerializer(typeof(MyObject));
string xml = null;
using (var ms = new MemoryStream())
{
dcs.WriteObject(ms, myobject);
xml = Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(xml);
// <Object><Frac>1/2</Frac></Object>
}
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
ms.Position = 0;
var obj = dcs.ReadObject(ms) as MyObject;
Console.WriteLine(obj.Frac);
// 1/2
}
}
}
这篇 MSDN 文章介绍了IDataContractSurrogate< /strong> 接口:
提供将一种类型替换为另一种类型所需的方法
序列化、反序列化期间的 DataContractSerializer
XML 模式文档的导出和导入。
虽然为时已晚,但仍然可以帮助某人。实际上,允许更改任何类的 XML。
您可以使用 DataContractSerializer 来完成此操作,尽管这种方式对我来说感觉很奇怪。您可以利用数据成员可以是私有变量这一事实,并使用私有字符串作为序列化成员。数据协定序列化程序还将在进程中的某些点执行标有 [On(De)Serializ(ed|ing)] 属性的方法 - 在这些属性内部,您可以控制 int 字段如何映射到字符串,以及反之亦然。缺点是您失去了类上 DataContractSerializer 的自动序列化魔力,现在需要维护更多逻辑。
无论如何,这就是我要做的:
[DataContract]
public class Fraction
{
[DataMember(Name = "Frac")]
private string serialized;
public int Numerator { get; private set; }
public int Denominator { get; private set; }
[OnSerializing]
public void OnSerializing(StreamingContext context)
{
// This gets called just before the DataContractSerializer begins.
serialized = Numerator.ToString() + "/" + Denominator.ToString();
}
[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
// This gets called after the DataContractSerializer finishes its work
var nums = serialized.Split("/");
Numerator = int.Parse(nums[0]);
Denominator = int.Parse(nums[1]);
}
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
如果您添加代表 Frac 元素的属性并向其应用 DataMember 属性而不是其他属性,您将得到您想要的我相信:
If you add a property that represents the Frac element and apply the DataMember attribute to it rather than the other properties you will get what you want I believe: