代码之家  ›  专栏  ›  技术社区  ›  ms5991

我可以使用自定义属性创建xmltattributeoverrides吗?

  •  1
  • ms5991  · 技术社区  · 6 年前

    我试图在自定义属性(称为 GenericSerializable . 本质上,当这个属性应用于公共属性时,我希望它向一些序列化程序(无论它是XML、JSON、Protobuf等)指示应该序列化该属性,如果它不存在,则不应该序列化它。目前,我可以获取特定属性是否具有该属性的信息,但我正在努力实现XML序列化程序。下面是我的测试继承结构:

    public abstract class SerializableObjectBase
    {
        protected int _typeIndicator;
    
        [GenericSerializable]
        public int TypeIndicator
        {
            get
            {
                return _typeIndicator;
            }
        }
    
        public SerializableObjectBase()
        {
            _typeIndicator = 0;
        }
    }
    
    public class SerializableObjectChildOne : SerializableObjectBase
    {
        private int _test;
    
        public int Test
        {
            get
            {
                return _test;
            }
            set
            {
                _test = value;
            }
        }
    
        public SerializableObjectChildOne() : base()
        {
            _test = 1234;
            _typeIndicator = 1;
        }
    }
    
    public class SerializableObjectChildTwo : SerializableObjectChildOne
    {        
        private List<int> _list;
    
        public List<int> List
        {
            get
            {
                return _list;
            }
        }
    
        public SerializableObjectChildTwo() : base()
        {
            _list = new List<int>();
            _typeIndicator = 2;
        }
    }
    

    我希望此示例的XML如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <SerializableObjectChildTwo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <TypeIndicator>2</TypeIndicator>
    </SerializableObjectChildTwo>
    

    但相反,它看起来是这样的:

    <?xml version="1.0" encoding="utf-8"?>
    <SerializableObjectChildTwo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Test>1234</Test>
    </SerializableObjectChildTwo>
    

    以下是序列化代码:

    using (FileStream fs = new FileStream(".\\output.xml", FileMode.Create))
    {
        // object to serialize
        SerializableObjectChildTwo s = new SerializableObjectChildTwo();
    
        XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    
        // check whether each property has the custom attribute
        foreach (PropertyInfo property in typeof(SerializableObjectChildTwo).GetProperties())
        {
            XmlAttributes attrbs = new XmlAttributes();
    
            // if it has the attribute, tell the overrides to serialize this property
            if (property.CustomAttributes.Any((attr) => attr.AttributeType.Equals(typeof(GenericSerializable))))
            {
                Console.WriteLine("Adding " + property.Name + "");
                attrbs.XmlElements.Add(new XmlElementAttribute(property.Name));
            }
            else
            {
                // otherwise, ignore the property
                Console.WriteLine("Ignoring " + property.Name + "");
                attrbs.XmlIgnore = true;
            }
    
            // add this property to the list of overrides
            overrides.Add(typeof(SerializableObjectChildTwo), property.Name, attrbs);
        }
    
        // create the serializer
        XmlSerializer xml = new XmlSerializer(typeof(SerializableObjectChildTwo), overrides);
    
        // serialize it
        using (TextWriter tw = new StreamWriter(fs))
        {
            xml.Serialize(tw, s);
        }
    }
    

    有趣的是,如果我加上 可泛型序列化 属性 List 中的属性 SerializableObjectChildTwo ,行为如预期。问题是,出于某种原因, Test 正在被序列化,尽管我添加了 attrbs.XmlIgnore = true TypeIndicator 没有被序列化,尽管事实上我将它显式添加到 XmlAttributeOverrides .

    我使用覆盖是否不正确?我不需要任何花哨的XML模式或任何东西,我只希望根据自定义属性的存在或不存在来序列化/不序列化公共属性。

    事先谢谢。

    2 回复  |  直到 6 年前
        1
  •  1
  •   dbc    6 年前

    1. XmlAttributeOverrides.Add (Type, String, XmlAttributes) type

      Test SerializableObjectChildTwo SerializableObjectChildOne

    2. TypeIndicator Why are properties without a setter not serialized XmlSerializer

    3. Introducing XML Serialization

      List

    4. Memory Leak using StreamReader and XmlSerializer

    public static class SerializableObjectBaseExtensions
    {
        static readonly Dictionary<Type, XmlSerializer> serializers = new Dictionary<Type, XmlSerializer>();
        static readonly object padlock = new object();
    
        public static XmlSerializer GetSerializer<TSerializable>(TSerializable obj) where TSerializable : SerializableObjectBase, new()
        {
            return GetSerializer(obj == null ? typeof(TSerializable) : obj.GetType());
        }
    
        public static XmlSerializer GetSerializer<TSerializable>() where TSerializable : SerializableObjectBase, new()
        {
            return GetSerializer(typeof(TSerializable));
        }
    
        static XmlSerializer GetSerializer(Type serializableType)
        {
            lock (padlock)
            {
                XmlSerializer serializer;
                if (!serializers.TryGetValue(serializableType, out serializer))
                    serializer = serializers[serializableType] = CreateSerializer(serializableType);
                return serializer;
            }
        }
    
        static XmlSerializer CreateSerializer(Type serializableType)
        {
            XmlAttributeOverrides overrides = new XmlAttributeOverrides();
    
            for (var declaringType = serializableType; declaringType != null && declaringType != typeof(object); declaringType = declaringType.BaseType)
            {
                // check whether each property has the custom attribute
                foreach (PropertyInfo property in declaringType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
                {
                    XmlAttributes attrbs = new XmlAttributes();
    
                    // if it has the attribute, tell the overrides to serialize this property
                    // property.IsDefined is faster than actually creating and returning the attribute
                    if (property.IsDefined(typeof(GenericSerializableAttribute), true))
                    {
                        Console.WriteLine("Adding " + property.Name + "");
                        attrbs.XmlElements.Add(new XmlElementAttribute(property.Name));
                    }
                    else
                    {
                        // otherwise, ignore the property
                        Console.WriteLine("Ignoring " + property.Name + "");
                        attrbs.XmlIgnore = true;
                    }
    
                    // add this property to the list of overrides
                    overrides.Add(declaringType, property.Name, attrbs);
                }
            }
    
            // create the serializer
            return new XmlSerializer(serializableType, overrides);
        }
    }
    

    here

        2
  •  1
  •   ms5991    6 年前

     overrides.Add(typeof(SerializableObjectChildTwo), property.Name, attrbs);
    

     overrides.Add(property.DeclaringType, property.Name, attrbs);