访问XmlAttributesOverrides在IXmlSerializable方法中添加了属性

时间:2010-12-01 21:03:20

标签: c# xml-serialization

如何使用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

所以...任何想法或替代品。 感谢您抽出宝贵时间。

2 个答案:

答案 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
    }
}