如何使用XmlAttributes
访问应用于IXmlSerializable
对象中字段的XmlAttributesOverrides
?
示例IXmlSerializable对象:
public class Person : SomeBaseClass, IXmlSerializable
{
public string Name1;
public string Name2;
[XmlIgnore]
public string Name3;
public Person()
{
}
public Person(string first, string second, string third)
{
Name1 = first;
Name2 = second;
Name3 = third;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
// ....
}
public void WriteXml(XmlWriter writer)
{
FieldInfo[] finfo = this.GetType().GetFields();
foreach (FieldInfo finf in finfo)
{
FieldAttributes attr = finf.Attributes;
object[] atts = finf.GetCustomAttributes(true);
if (atts.Length == 0)
{
// handle field with no attributes ... should be just Name1
// but also get Name2 since XmlAttributOverrides' XmlIgnore is not
// included with GetCustomAttributes results.
writer.WriteElementString(finf.Name, (string)finf.GetValue(this));
}
else
{
// handle field with attributes ... should be Name2 and Name3
// but only get Name3 via [XmlIgnore] compiler generated attribute
}
}
}
}
典型覆盖创建:
// parent app ...
public XmlSerializer CreateOverrider()
{
XmlAttributeOverrides xOver = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
attrs.XmlIgnore = true;
xOver.Add(typeof(Person), "name2", attrs);
XmlSerializer xSer = new XmlSerializer(typeof(Person), xOver);
return xSer;
}
private void button2_Click(object sender, EventArgs e)
{
// Custom XmlSerialize
Person pson = new Person("First", "Second", "Third");
XmlSerializer serializer = CreateOverrider();
TextWriter writer = new StreamWriter("PersonOverride.xml");
serializer.Serialize(writer, pson);
writer.Close();
}
// etc ...
创建输出:
<?xml version="1.0" encoding="utf-8"?><Person><Name1>First</Name1><Name2>Second</Name2></Person>
我需要使用IXmlSerializable
来克服'SomeBaseClass'中的继承问题。
问题是GetCustomArributes
没有返回添加到XmlAttributeOverrides
集合中的任何属性 - 或者我做错了!?
GetCustomAttributes
也可能不支持返回这些添加的属性,或者我不应该在XmlAttributeOverrides
类中使用IXmlSerializable
。
所以...任何想法或替代品。 感谢您抽出宝贵时间。
答案 0 :(得分:0)
没有办法做到这一点。
原因是,当给定的对象不是XmlSerializer
时,IXmlSerializable
将生成序列化程序类。那些XML覆盖属性将用于以不同方式编译这些类。 XML覆盖属性在序列化或反序列化期间不在运行时应用;这就是他们无法访问的原因。
继承IXmlSerializable
的类不会生成序列化程序类。如果要使用XML覆盖属性,则必须不要覆盖序列化程序类编译器。使用Person
的这个实现,让它根据给定的覆盖为你生成序列化器类(也会运行很多倍):
public class Person : SomeBaseClass
{
public string Name1;
public string Name2;
[XmlIgnore]
public string Name3;
public Person()
{
}
public Person(string first, string second, string third)
{
Name1 = first;
Name2 = second;
Name3 = third;
}
}
当然,您也可以编写自己的序列化程序类编译器,但这比这里适合的更复杂。但实现应该是这样的:
public static Type GeneratePersonSerializer(XmlAttributeOverrides overrides) {
//here compile a class to generate a Type inheriting from IXmlSerializable
//the serializer logic in this class should be generated by taking into
//account the given XmlAttributeOverrides
//the type returned should be the Type passed into new XmlSerializer(Type type)
}
答案 1 :(得分:0)
可以使用FieldInfo列表创建自己的 XmlWriter 实现,您可以在其中存储对要序列化的字段的引用。然后将其传递给目标类型的实例(示例中为 Person )并仅对它们进行序列化。在main方法中,您可以看到2个序列化示例:使用Name1而不使用Name1。并且还应注意反射性能很慢,因此可能只是创建bool字段( bool DoNotSerializeName1 ),如果它将为true,则忽略Name1序列化。希望它对某人有用......
人员类型和序列化示例:
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace XmlCustomSerializer
{
public class Person : IXmlSerializable
{
public string Name1;
public string Name2;
[XmlIgnore]
public string Name3;
public Person()
{
}
public Person(string first, string second, string third)
{
Name1 = first;
Name2 = second;
Name3 = third;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
// ....
}
private static FieldInfo[] _cachedFields = null;
public void WriteXml(XmlWriter writer)
{
var customWriter = writer as XmlCustomWriter;
if (customWriter == null)
throw new ArgumentException("writer");
if (_cachedFields == null)
{
_cachedFields = typeof(Person).GetFields();
}
foreach (FieldInfo finf in customWriter.FieldsToSerialize)
{
if (_cachedFields.Contains(finf))
{
writer.WriteElementString(finf.Name, (string)finf.GetValue(this));
}
}
}
}
class Program
{
static void Main(string[] args)
{
var person = new Person
{
Name1 = "Some",
Name2 = "Person",
Name3 = "Name"
};
var settings = new XmlWriterSettings { Indent = true, Encoding = Encoding.ASCII };
var allFields = typeof(Person).GetFields();
XmlSerializer xSer = new XmlSerializer(typeof(Person));
using (var stream = new MemoryStream())
{
var xmlCustomWriter = new XmlCustomWriter(
XmlWriter.Create(new StreamWriter(stream), settings));
//serialize all fields
xmlCustomWriter.FieldsToSerialize = allFields;
xSer.Serialize(xmlCustomWriter, person);
stream.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(stream).ReadToEnd());
}
using (var stream = new MemoryStream())
{
var xmlCustomWriter = new XmlCustomWriter(
XmlWriter.Create(new StreamWriter(stream), settings));
//serialize 2 fields
xmlCustomWriter.FieldsToSerialize = allFields.Skip(1);
xSer.Serialize(xmlCustomWriter, person);
stream.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(stream).ReadToEnd());
}
Console.Read();
}
}
}
XmlCustomWriter实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
namespace XmlCustomSerializer
{
public class XmlCustomWriter : XmlWriter
{
private readonly XmlWriter _innerWriter;
public XmlCustomWriter(XmlWriter innerWriter)
{
if (innerWriter == null)
throw new ArgumentNullException("innerWriter");
_innerWriter = innerWriter;
FieldsToSerialize = Enumerable.Empty<FieldInfo>();
}
public IEnumerable<FieldInfo> FieldsToSerialize { get; set; }
#region Implement XmlWriter
public override void Flush()
{
_innerWriter.Flush();
}
public override string LookupPrefix(string ns)
{
return _innerWriter.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
_innerWriter.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
_innerWriter.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
_innerWriter.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
_innerWriter.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
_innerWriter.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
_innerWriter.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
_innerWriter.WriteEndAttribute();
}
public override void WriteEndDocument()
{
_innerWriter.WriteEndDocument();
}
public override void WriteEndElement()
{
_innerWriter.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
_innerWriter.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
_innerWriter.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
_innerWriter.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
_innerWriter.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
_innerWriter.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
_innerWriter.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument(bool standalone)
{
_innerWriter.WriteStartDocument(standalone);
}
public override void WriteStartDocument()
{
_innerWriter.WriteStartDocument();
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
_innerWriter.WriteStartElement(prefix, localName, ns);
}
public override WriteState WriteState
{
get { return _innerWriter.WriteState; }
}
public override void WriteString(string text)
{
_innerWriter.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
_innerWriter.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteWhitespace(string ws)
{
_innerWriter.WriteWhitespace(ws);
}
#endregion Implement XmlWriter
}
}