我有一个对象 Foo,我将其序列化为 XML 流。
public class Foo {
// The application version, NOT the file version!
public string Version {get;set;}
public string Name {get;set;}
}
Foo foo = new Foo { Version = "1.0", Name = "Bar" };
XmlSerializer xmlSerializer = new XmlSerializer(foo.GetType());
它工作起来快速、简单,并且可以完成当前所需的一切。
我遇到的问题是我需要维护一个单独的文档文件,其中包含一些小注释。如上例所示,Name
很明显,但 Version
是应用程序版本,而不是我们在本例中所期望的数据文件版本。我还有很多类似的小事情想通过评论来澄清。
我知道如果我使用 WriteComment()
函数手动创建 XML 文件,我就可以做到这一点,但是是否可以实现一个可能的属性或替代语法,以便我可以继续使用序列化器功能?
I have an object Foo which I serialize to an XML stream.
public class Foo {
// The application version, NOT the file version!
public string Version {get;set;}
public string Name {get;set;}
}
Foo foo = new Foo { Version = "1.0", Name = "Bar" };
XmlSerializer xmlSerializer = new XmlSerializer(foo.GetType());
This works fast, easy and does everything currently required.
The problem I'm having is that I need to maintain a separate documentation file with some minor remarks. As in the above example, Name
is obvious, but Version
is the application version and not the data file version as one could expect in this case. And I have many more similar little things I want to clarify with a comment.
I know I can do this if I manually create my XML file using the WriteComment()
function, but is there a possible attribute or alternative syntax I can implement so that I can keep using the serializer functionality?
发布评论
评论(6)
可能迟到了,但当我尝试使用 Kirill Polishchuk 解决方案反序列化时遇到了问题。最后我决定在序列化 XML 后对其进行编辑,解决方案如下所示:
Probably late to the party but I had problems when I was trying to deserialize using Kirill Polishchuk solution. Finally I decided to edit the XML after serializing it and the solution looks like:
用户 dbc 提出的解决方案看起来不错,但是与使用知道的 XmlWriter 相比,它似乎需要更多的手动工作来创建此类注释如何根据 XmlComment 属性插入注释。
请参阅 https://archive.codeplex.com/?p=xmlcomment - 看来你可以将这样的编写器传递给 XmlSerializer,因此不必实现您自己的序列化,这可能很棘手。
不过,我自己最终还是使用了 dbc 的解决方案,干净整洁,没有额外的代码。请参阅https://dotnetfiddle.net/Bvbi0N。确保为注释元素(XmlAnyElement)提供“set”访问器。顺便说一句,它不需要有名字。
更新:最好始终传递唯一的名称,即使用 [XmlAnyElement("someCommentElement")] 而不是 [XmlAnyElement]。在 WCF 中使用相同的类,它被那些没有提供名称的 XmlAnyElements 阻塞,尽管我对它们都有 [XmlIgnore、SoapIgnore、IgnoreDataMember]。
Proposed solution by user dbc looks fine, however it seems to need more manual work to create such comments than using an XmlWriter that knows how to insert comments based on XmlComment attributes.
See https://archive.codeplex.com/?p=xmlcomment - it seems you can pass such a writer to XmlSerializer and thus not have to implement your own serialization which could be tricky.
I did myself end up using dbc's solution though, nice and clean with no extra code. See https://dotnetfiddle.net/Bvbi0N. Make sure you provide a "set" accessor for the comment element (the XmlAnyElement). It doesn't need to have a name btw.
Update: better pass a unique name always, aka use [XmlAnyElement("someCommentElement")] instead of [XmlAnyElement]. Was using the same class with WCF and it was choking upon those XmlAnyElements that didn't have a name provided, even though I had [XmlIgnore, SoapIgnore, IgnoreDataMember] at all of them.
对于嵌套的 xml,我以这种方式更改了方法(对我来说,我有简单的属性作为字符串(有可能使其逻辑更加复杂)
for nested xml, I changed the method this way(for me i was having simple property as string(its possible to make it more complex in the logic)
通过使用返回
XmlComment
并用[XmlAnyElement("SomeUniquePropertyName")]
。即,如果您向
Foo
添加一个属性,如下所示:将生成以下 XML:
但是,问题要求的不止于此,即某种在文档系统中查找注释的方法。以下代码通过使用扩展方法根据反射的注释属性名称查找文档来实现此目的:
为此生成以下 XML:
注意:
扩展方法
XmlCommentExtensions.GetXmlCommentAttribute(this Type type, string memberName )
假定注释属性将命名为xxxXmlComment
,其中xxx
是“真实”属性。如果是这样,它可以通过使用CallerMemberNameAttribute
。这可以通过传入真实姓名手动覆盖。一旦知道类型和成员名称,扩展方法就会通过搜索应用于属性的
[XmlComment]
特性来查找相关注释。这可以替换为对单独文档文件的缓存查找。虽然仍然需要为每个可能被注释的属性添加
xxxXmlComment
属性,但这可能比 直接实现IXmlSerialized
这是相当棘手的,可能会导致反序列化中的错误,并且可能需要复杂子属性的嵌套序列化。要使
XmlSerializer
序列化属性,它必须同时具有 getter 和 setter。因此,我提供了不执行任何操作的注释属性设置器。工作 .Net fiddle。
This is possible using the default infrastructure by making use of properties that return an object of type
XmlComment
and marking those properties with[XmlAnyElement("SomeUniquePropertyName")]
.I.e. if you add a property to
Foo
like this:The following XML will be generated:
However, the question is asking for more than this, namely some way to look up the comment in a documentation system. The following accomplishes this by using extension methods to look up the documentation based on the reflected comment property name:
For which the following XML is generated:
Notes:
The extension method
XmlCommentExtensions.GetXmlCommentAttribute(this Type type, string memberName)
assumes that the comment property will be namedxxxXmlComment
wherexxx
is the "real" property. If so, it can automatically determine the real property name by marking the incomingmemberName
attribute withCallerMemberNameAttribute
. This can be overridden manually by passing in the real name.Once the type and member name are known, the extension method looks up the relevant comment by searching for an
[XmlComment]
attribute applied to the property. This could be replaced with a cached lookup into a separate documentation file.While it is still necessary to add the
xxxXmlComment
properties for each property that might be commented, this is likely to be less burdensome than implementingIXmlSerializable
directly which is quite tricky, can lead to bugs in deserialization, and can require nested serialization of complex child properties.To ensure that each comment precedes its associated element, see Controlling order of serialization in C#.
For
XmlSerializer
to serialize a property it must have both a getter and setter. Thus I gave the comment properties setters that do nothing.Working .Net fiddle.
使用默认基础设施是不可能的。您需要根据您的目的实现
IXmlSerialized
。非常简单的实现:
输出:
另一种方式,也许更好:使用默认序列化程序序列化,然后执行后处理,即更新 XML,例如使用
XDocument
或XmlDocument
。Isn't possible using default infrastructure. You need to implement
IXmlSerializable
for your purposes.Very simple implementation:
Output:
Another way, maybe preferable: serialize with default serializer, then perform post-processing, i.e. update XML, e.g. using
XDocument
orXmlDocument
.序列化后在 xml 末尾添加注释(神奇的是刷新 xmlWriter)。
Add comment at the end of xml after serialization (magic is to flush xmlWriter).