views:

321

answers:

1

I have a class I am serializing with C#'s XmlSerializer. It is marked with the XmlRoot attribute, and I would like to inherit this attribute in a derived class.

Looking at the documentation it does not say that XmlRoot sets Inherit to false with AttributeUsageAttribute (Inherit is supposed to default to true), but I get an error when trying to deserialize my inherited class without an XmlRoot attribute ("<rootNode xmlns=''> was not expected.").

This currently works:

[Serializable()]
[XmlRoot("rootNode")]
public class BaseClass
{
    [XmlAttribute("attributeA")]
    public int A { get; set; }
}

[Serializable()]
[XmlRoot("rootNode")]
public class InheritedClass : BaseClass
{
    [XmlElement("elementB")]
    public int B { get; set; }
}

This does not work, but is what I want:

[Serializable()]
[XmlRoot("rootNode")]
public class BaseClass
{
    [XmlAttribute("attributeA")]
    public int A { get; set; }
}

[Serializable()]
public class InheritedClass : BaseClass
{
    [XmlElement("elementB")]
    public int B { get; set; }
}

The XML I might try to deserialize as a InheritedClass looks like this:

<rootNode attributeA="abc">
    <elementB>123</elementB>
</rootNode>
+4  A: 

The Inherited propertly merely indicates that the attribute can be inherited, not that it will be. For example, if you look at the type signature for MemberInfo.GetCustomAttributes, which is the most common way to retrieve these attributes, it has this overload:

public abstract Object[] GetCustomAttributes(bool inherit)

If the parameter inherit is true, then the method will search the inheritance chain, i.e. it will look to see if the base class or any ancestor classes have the attribute, if the specific type being looked at does not. In order for this method to find an attribute on an inherited class, the attribute class itself must not set AttributeUsage.Inherited = false.

However, if the attribute's AttributeUsage.Inherited is true, the GetCustomAttributes method will still ignore it if the inherit parameter is false.

In other words, AttributeUsage.Inherited is a permission, not a requirement. It is completely up to whomever invokes GetCustomAttributes (or a similar method) to decide whether or not to obtain inherited attributes. You can't control this. I'm fairly certain (not 100% positive) that the XmlSerializer does not look for inherited attributes.

Maybe not the answer you were looking for, but there you are; looks like you've already figured out the workaround.

Incidentally, the way it works with XML serialization is that the XmlSerializer uses the XmlReflectionImporter which in turn gets an instance of XmlAttributes. Here is what the constructor looks like for XmlAttributes (out of Reflector):

public XmlAttributes(ICustomAttributeProvider provider)
{
    this.xmlElements = new XmlElementAttributes();
    this.xmlArrayItems = new XmlArrayItemAttributes();
    this.xmlAnyElements = new XmlAnyElementAttributes();
    object[] customAttributes = provider.GetCustomAttributes(false);
    ...
}

So you can see that it does in fact pass false to the GetCustomAttributes method; it does not look for attributes in base classes, even if those attributes are "inheritable."

Aaronaught
Thorough response, I appreciate the background. Thanks!
emddudley