如何使用派生类在Xml中编写?

时间:2012-05-02 03:44:28

标签: c# xml xml-serialization

也许标题不是最好的描述。

我的情况是,根据一个接口,我想写一个属于object的属性。请观看以下示例:

public interface IFoo
{
    // anothers properties...
    object Value { get; }
}

我在这里有三个实现,检查Value是否隐藏了真正的数据类型。

public class FooA : IFoo
{
    public string Value { get; set; }
    object IFoo.Value { get { return Value; } }
}

public class FooB : IFoo
{
    public int Value { get; set; }
    object IFoo.Value { get { return Value; } }
}

public class FooC : IFoo
{
    public List<double> Value { get; set; }
    object IFoo.Value { get { return Value; } }
}

在我的场景中,非常重要的是不使用泛型。因此,通过这个实现,我需要在Xml中写入属性Value。

例如:

    static void Main(string[] args)
    {
        List<IFoo> fooList = new List<IFoo>()
        {
            new FooA() { Value = "String" },
            new FooB() { Value = 2 },
            new FooC() { Value = new List<double>() {2, 3.4 } } 
        };

        // Write in a Xml the elements of this list with the property Value (and the problem is the datartype,
        // strings, ints, lists, etc)
        // ...
    }

我在想使用XmlSerialization,但我不想存储对象的所有属性,只是存储Value属性。

我需要一种方法来编写属性Value(不存储该接口的所有属性)以及一种了解我正在使用的IFoo实现的方法。

更新:我想要一个像这样的XML文件。

<Foos>
    <Foo xsi:Type="FooA" Value="String" />
    <Foo xsi:Type="FooB" Value="2" />
    <Foo xsi:Type="FooC" >
        <Value>
            <List xsi:Type="Double">
                <Element>2</Element>
                <Element>3.4</Element>
            </List>
        </Value>
    </Foo
</Foos>

这只是一个想法。我们的想法是只存储IFoo的属性以及使用值获取具体对象的能力。

更新:

感谢Raj Nagalingam帮我解决这个问题。这就是我所做的。

public interface IFoo
{
    object Value { get; }
}

public abstract class Foo<T> : IFoo, IXmlSerializable
{
    [XmlElement]
    public T Value { get; set; }
    [XmlIgnore]
    object IFoo.Value { get { return Value; } }

    XmlSchema IXmlSerializable.GetSchema() { return null; }
    void IXmlSerializable.ReadXml(XmlReader reader) { throw new NotImplementedException(); }
    void IXmlSerializable.WriteXml(XmlWriter writer)
    {
        XmlSerializer serial = new XmlSerializer(Value.GetType());
        serial.Serialize(writer, Value);
    }
}

public class FooA : Foo<string> { }
public class FooB : Foo<int> { }
public class FooC : Foo<List<Double>> { }
public class FooContainer : List<IFoo>, IXmlSerializable
{
    public XmlSchema GetSchema() { return null; }
    public void ReadXml(XmlReader reader) { throw new NotImplementedException(); } 
    public void WriteXml(XmlWriter writer)
    {
        ForEach(x => 
            {
                XmlSerializer serial = new XmlSerializer(x.GetType());
                serial.Serialize(writer, x);
            });
    }
}

class Program
{
    static void Main(string[] args)
    {
        FooContainer fooList = new FooContainer()
        {
            new FooA() { Value = "String" },
            new FooB() { Value = 2 },
            new FooC() { Value = new List<double>() {2, 3.4 } } 
        };

        XmlSerializer serializer = new XmlSerializer(fooList.GetType(),
            new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
        System.IO.TextWriter textWriter = new System.IO.StreamWriter(@"C:\temp\demo.xml");
        serializer.Serialize(textWriter, fooList);
        textWriter.Close();
    }
}

它有效,但我想用具体类恢复列表是不可能的。使用标准序列化我看到它是用xsi编写的,这次我看不到它们。如何恢复我的物体?

1 个答案:

答案 0 :(得分:1)

以下是实现它的方法之一,请看一下,并根据您的需要进行扩展/重构。我希望它有所帮助。

public interface IFoo : IXmlSerializable
{
    // anothers properties...
    object Value { get; }
}

[XmlRoot("Foo")]
public class FooA : IFoo
{
    public string Value { get; set; }
    object IFoo.Value { get { return Value; } }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Foo");

        writer.WriteStartAttribute("Type", "http://example.com/2007/ns1");
        writer.WriteString(GetType().Name);
        writer.WriteEndAttribute();

        writer.WriteStartAttribute("Value");
        writer.WriteString(Value.ToString());
        writer.WriteEndAttribute();

        writer.WriteEndElement();

    }

    #endregion
}

[XmlRoot("Foo")]
public class FooB : IFoo
{
    public int Value { get; set; }
    object IFoo.Value { get { return Value; } }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Foo");

        writer.WriteStartAttribute("Type", "http://example.com/2007/ns1");
        writer.WriteString(GetType().Name);
        writer.WriteEndAttribute();

        writer.WriteStartAttribute("Value");
        writer.WriteString(Value.ToString());
        writer.WriteEndAttribute();

        writer.WriteEndElement();
    }

    #endregion
}

[XmlRoot("Foo")]
public class FooC : IFoo
{
    public List<double> Value { get; set; }
    object IFoo.Value { get { return Value; } }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteStartElement("Foo");

        writer.WriteStartAttribute("Type", "http://example.com/2007/ns1");
        writer.WriteString(GetType().Name);
        writer.WriteEndAttribute();

        writer.WriteStartElement("Value");

        if (Value != null)
        {
            writer.WriteStartElement("List");

            writer.WriteStartAttribute("Type", "http://example.com/2007/ns1");
            writer.WriteString(typeof(double).Name);
            writer.WriteEndAttribute();

            foreach (double value in Value)
            {
                writer.WriteElementString("Element", value.ToString());
            }

            writer.WriteEndElement();

        }

        writer.WriteEndElement();

        writer.WriteEndElement();
    }

    #endregion
}

[XmlRoot("Foos")]
public class ListCotainer : List<IFoo>, IXmlSerializable
{
    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteAttributeString("xmlns", "xsi", null, "http://example.com/2007/ns1");
        foreach (IFoo foo in this)
        {
            foo.WriteXml(writer);
        }
    }

    #endregion
}
class Program
{
    static void Main(string[] args)
    {
        XmlWriterSettings _xws = new XmlWriterSettings();
        _xws.OmitXmlDeclaration = true;
        _xws.ConformanceLevel = ConformanceLevel.Auto;
        _xws.Indent = true;

        ListCotainer container = new ListCotainer()
        {
                new FooA() { Value = "String" },
                new FooB() { Value = 2 },
                new FooC() { Value = new List<double>() {2, 3.4 } } 
        };

        StringBuilder xmlString = new StringBuilder();
        using (XmlWriter xtw = XmlTextWriter.Create(xmlString, _xws))
        {
            XmlSerializer serializer = new XmlSerializer(container.GetType());
            serializer.Serialize(xtw, container);

            xtw.Flush();
        }
        Console.WriteLine(xmlString.ToString());
    }
}