Serialize Base Class Implementation for all “new”

2019-09-02 02:06发布

I have a bunch of classes that were auto-generated from an XSD, and provided to me in a compiled DLL for which I don't have the source code. I have a need to add interfaces to each of the types, which resulted in code such as the following:

public interface IBar
{
    string SomeProperty { get; set; }
}

public interface IFoo<TBar> where TBar : IBar
{
    TBar Bar { get; set; }
}

public class BarWrapper : BarFromXSD, IBar
{
}

public class FooWrapper : FooFromXSD, IFoo<BarWrapper>
{
    [XmlElement("bar")]
    public new BarWrapper Bar
    {
        get { return base.Bar as BarWrapper; }
        set { base.Bar = value; }
    }
}

If the client gives me a DLL where any of the interfaces to the underlying types changes, I will get compile-time errors telling me such. However, that is NOT true if the serialization attributes change in the underlying DLL. In that case, my wrapper classes will happily serialize into objects that are incompatible with the associated XSDs.

The other issue with the above code is that it simply doesn't work. When I try to create an XmlSerializer for objects of type FooWrapper, I get the exception chain:

There was an error reflecting type 'MyNamespace.FooWrapper'.
There was an error reflecting property 'Bar'.
Member FooWrapper.Bar of type MyNamespace.BarWrapper hides base class member cs_Foo.Bar of type DLLNamespace.Bar. Use XmlElementAttribute or XmlAttributeAttribute to specify a new name.

To avoid this issue, I would like to do the simpler of either:

1) Override default serialization, in order to ignore the "new" property implementations, or
2) Reflectively copy all XML serialization attributes from the base class to the derived class

The issues that I am trying to address with any potential solution are:

1) I would like to perform reflection once, in the static constructor, to determine the serialized element/attribute names and namespaces.
2) I have multiple classes that follow the same pattern as FooWrapper, so any solution should would work for any such classes.
3) The classes that follow the FooWrapper pattern can contain other properties not defined in the base class that require serialization.
4) The ideal solution should gracefully handle new properties. For example, if at a later time I add or remove a "new" property, I shouldn't have to add/remove other methods, or have to hard-code the name of the "new" property in the static constructor.

Any insight to a solution that meets these requirements is greatly appreciated.

1条回答
相关推荐>>
2楼-- · 2019-09-02 03:03

Here is a very simple example of xml with inheritance.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication51
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            Root root = new Root() {
                bar = new Bar1() {
                    foo = "123"
                }
            };


            XmlSerializer serializer = new XmlSerializer(typeof(Root));

            StreamWriter writer = new StreamWriter(FILENAME);
            XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
            _ns.Add("", "");
            serializer.Serialize(writer, root, _ns);
            writer.Flush();
            writer.Close();
            writer.Dispose();

        }
    }

    [XmlRoot("Root")]
    public class Root 
    {
        public Bar bar {get;set;}
    }

    [XmlInclude(typeof(Bar1))]
    [XmlRoot("Bar")]
    public class Bar 
    {
    }

    [XmlRoot("Bar1")]
    public class Bar1 : Bar
    {
        [XmlElement("foo")]
        public string foo {get;set;}
    }
}

Look at the XML. A 'type' attribute is added.

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <bar d2p1:type="Bar1" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance">
    <foo>123</foo>
  </bar>
</Root>
查看更多
登录 后发表回答