1

I'm running into an issue with Xml serialization of my own class. It is a derived class, which doesn't naturally have a parameterless constructor - I had to add one just for the sake of serialization. Of course, because of that I'm running into dependency/order issue.

Here's a simplification, which I hope still illustrates the problem (I reserve the right to augment the illustration if it turns out I didn't capture the problem - I just didn't want to dump a complicated Object Model on you :))

public class Base{
  public virtual Vector Value{ get; set;}
}

public class Derived : Base{

  public Vector Coefficient { get; set; }
  public override Vector Value{
     get { return base.Value * Coefficient; }
     set { base.Value = value / Coefficient; }
  }
}

EDIT: to avoid confusion, I substituted the value type double in the original post with a not-shown-here Vector type

When XmlSerializer de-serializes Derived, I run into null value exception - Both base.Value and this.Coefficient are null.

Is there any way to fix this?

13
  • 1
    Those are value types and can't really be null. Post the exact exception info. Commented Jul 15, 2013 at 21:12
  • @HenkHolterman: granted. This is a simplification - in the real case these are not value types and they are null - I checked with a debugger. Commented Jul 15, 2013 at 21:15
  • have you tried [XmlInclude(typeof(Derived))]? Commented Jul 15, 2013 at 21:17
  • @terrybozzio - I have, actually (without fully understanding what it does). It returns a compiler-time error: Attribute 'System.Xml.Serialization.XmlInclude' is not valid on this declaration type. It is only valid on 'class, struct, method, interface' declarations. Commented Jul 15, 2013 at 21:20
  • 1
    Making correct usage dependent on the order in which properties are accessed / assigned is simply a design mistake, to be honest. You might be able to influence it a bit with the Order property on XmlElementAttribute, but my advice: find a design that doesn't depend on property access/assignment order. Commented Jul 15, 2013 at 21:24

3 Answers 3

2

It seems that a lot of the issues here stem from using your domain model for serialization. Now, this can work, but it can also be hugely problematic if your domain model deviates even slightly from what the serializer wants to do.

I strongly suggest trying to add a second parallel representation of the data, as a "DTO model" - meaning: a set of objects whose job is to represent the data for serialization. S instead of a complicated property with calculations and dependencies, you just have:

public double SomeValue { get; set; }

etc. The key point is that is is simple and represents the data, not your system's rules. You serialize to/from this model - which should not be simple - and you map this to/from your domain model. Conversion operators can be useful, but a simple "ToDomainModel" / "FromDomainModel" method works fine too. Likewise, tools like AutoMapper might help, but 15 lines of DTO-to/from-Domain code isn't going to hurt either.

This avoids issues with:

  • constructors
  • non-public members
  • assignment order
  • read-only members
  • versioning

And a range of other common pain points in serialization.

Sign up to request clarification or add additional context in comments.

3 Comments

I think I get what you're saying. Thanks!
One more question. I put XmlIgnore on the Derived.Value, but it is still being called by the XmlSerializer. I'm guessing it's because the vase property is virtual. The base.Value is actually not a "domain model" per se - it is barebones property. Any advice?
@NewDev the serializer will look at the declared values. Obviously the problem would go away in a DTO, but you could also use XmlAttributeOverrides - noting tht doing this means you need to cache and reuse the serializer instance manually. Or you will leak memory faster than you realise was possible.
1

You need to tell the serializer that your base object has derived items. Try:

[XmlInclude(typeof(Derived))]
public class Base {

Alternatively, you can explain this at run time with:

public XmlSerializer(Type type, Type[] extraTypes){..}

In your case: new XmlSerializer(typeof(Base), new Type[] { typeof(Derived), ..});

And to make things even more generic, if there is a huge hierarchy, you can use reflection to get a list of the derived types:

// You'll want to cache this result, and it could be a lot of work to run this
// multiple times if you have lots of classes
var knownTypes = Assembly.GetExecutingAssembly().GetTypes().Where(
t => typeof(Base).IsAssignableFrom(t)).ToArray();
var serializer = new XmlSerializer(typeof(Base), knownTypes);

3 Comments

That complicates stuff because in real case I have multiple levels of subclasses. In fact I don't even know how to declare it since the Base the Derived class generic, i.e. Derived<T> : Base.
Ahh, then you will need to use reflection. I'll update the above to give you a guide on how to do this (this will save you having to mirror your structure with a DTO approach)
But in your case, you have business division logic in the override which will cause div by 0 issues etc depending on the deserialization
0

One problem with your Value getter and setter is that if Coefficient is not loaded at the time when de-serializing the Value, then it will cause divide by zero errors. Even worse, it might not break, but instead, actually do the calculation against an incorrect value since Coefficient may have a pre-deserialization value stored in it. The following will solve the divide by zero situation, and hopefully update value correctly if coefficient loads second. In truth, these situations are usually handled better by serializing the non calculated value and then using [XmlIgnoreAttribute] on the derived property.

public class Derived : Base{


    public override double Value{
       get { return _coefficient; }
       set { 
          if(Coefficient == 0){
          base.Value = value;
       }else{
           base.Value = value / Coefficient; 
       }
    }

   private double _coefficient;
   public double Coefficient{
       get { return _coefficient; }
       set { 
           if(Coefficient == 0)
           {
               temp = base.Value;
               _coefficient = value;
               Value = temp; 
           }
           else{
                _coefficient = value;
           }
    }

}


// Example by serializing unmodified value
public double Coefficient { get; set; }
public double BaseValue { get; set; }

[XmlIgnoreAttribute]
public double Value
{
   get { return BaseValue * Coefficient; }
   set 
   { 
         if(Coefficient != 0){
            BaseValue = value / Coefficient;
         }else{
            BaseValue = value;
         }
    }

3 Comments

this unfortunately only solves the simplified example I gave... My problem is not with division by zero, but with the fact that some values have not yet been instantiated before they are needed.
The main thing is you should probably serialize simple representations that don't depend on other values like my second example, and ignore properties that are derived, otherwise you will likely get unexpected problems from serialization including messed up values.
yeah, looks like that's what Marc suggested as well. +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.