views:

166

answers:

4

Suppose I have the following (trivially simple) base class:

public class Simple
{
    public string Value { get; set; }
}

I now want to do the following:

public class PathValue : Simple
{
    [XmlAttribute("path")]
    public string Value { get; set; }
}

public class ObjectValue : Simple
{
    [XmlAttribute("object")]
    public string Value { get; set; }
}

But without actually redefining the property. I want to apply attributes to members of the base class. Is this possible?

The real problem is that in my serialization mechanism from/to XML (which works brilliantly btw), I find a lot of similar elements where only the names of the attributes differ (they're not consistent, and I don't control the format). Right now I need to create a different class for every such element, whereas they're like 100% the same (apart from the attributes).

I don't think it's possible, but you might never know.

UPDATE:

I tried Marc's approach, but to no avail:

public class Document
{
    public PathValue Path;
    public ObjectValue Object;
}

class Program
{
    static void Main(string[] args)
    {
        var doc = new Document()
        {
            Path = new PathValue() { Value = "some path" },
            Object = new ObjectValue() { Value = "some object" }
        };

        XmlAttributeOverrides overrides = new XmlAttributeOverrides();

        overrides.Add(typeof(PathValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("path") });
        overrides.Add(typeof(ObjectValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("object") });

        XmlSerializer serializer = new XmlSerializer(typeof(Document), overrides);

        serializer.Serialize(Console.Out, doc);

        Console.WriteLine();
        Console.ReadLine();
    }
}

...doesn't do the trick.

+1  A: 

Could you perhaps use the overload XmlSerializer constructor that lets you pass in the attributes to apply at runtime? Then you don't have to worry about it...

caveat: you want to cache the serializer instance and re-use it; otherwise (with the complex constructors) it does dynamic type generation each time.

Example:

using System;
using System.Xml.Serialization;
public class Simple {
    public string Value { get; set; }

    static void Main() {
        XmlAttributeOverrides overrides = new XmlAttributeOverrides();
        overrides.Add(typeof(Simple), "Value", new XmlAttributes {
           XmlAttribute = new XmlAttributeAttribute("path")
        });
        XmlSerializer pathSerializer = new XmlSerializer(
            typeof(Simple), overrides);
        // cache and re-use pathSerializer!!!

        Simple obj = new Simple();
        obj.Value = "abc";
        pathSerializer.Serialize(Console.Out, obj);
    }
}

Output:

<Simple xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" path="abc" />
Marc Gravell
While that may work, it doesn't allow me to specify the override on the derived classes. So then I should have a serializer for each instance in which the name of the attribute is different, while all these different elements may appear in the same document.
Dave Van den Eynde
A: 

You are probably aware of this, but as an idea (although the code structure would completely change in that case):

One way would be to serialize the base class as a collection of name-value pairs, using custom serialization (there is also XDocument and similar helpful stuff to make it easier). Although it doesn't enforce type safety, it would spare you from doing lots of manual work.

I also prefer going for custom serialization because it allows a wider range of possibilities (serializing immutable classes, for example). XmlSerializer is also really nasty sometimes (e.g. I hate adding the "MyFieldSpecified" property to create optional attributes).

Groo
In my application, I have a special model just for the generation of XML. That means that we have a "domain model" and a "xml model", and the two are really separated. I decided to use this approach to generating our XML files over using XmlWriter because of the customizability of the XmlSerializer.Our domain model is serialized using BinaryFormatter.
Dave Van den Eynde
A: 

Perhaps you can mark the base class property with a common mapping, than you only override the property in inherited classes where it should be different. At least you would save some overriding.

Enyra
+1  A: 

I'm going to answer this question myself, so that I can accept this answer. I don't like the answer, but I suppose it's the only valid answer.

The answer is: No, you can't do it.

Dave Van den Eynde