views:

179

answers:

1

I'm trying to use XmlSerializer from C# to save out a class that has some values that are read by properties (the code being just a simple retrieval of field value) but set by setter functions (since there is a delegate called if the value changes).

What I'm currently doing is this sort of thing. The intended use is to use the InT property to read the value, and use SetInT to set it. Setting it has side-effects, so a method is more appropriate than a property here. XmlSerializationOnly_InT exists solely for the benefit of the XmlSerializer (hence the name), and shouldn't be used by normal code.

class X
{
    public double InT
    {
        get { return _inT; }
    }

    public void SetInT(double newInT)
    {
        if (newInT != _inT)
        {
            _inT = newInT;
            Changed();//includes delegate call; potentially expensive
        }
    }

    private double _inT;

    // not called by normal code, as the property set is not just a simple
    // field set or two.
    [XmlElement(ElementName = "InT")]
    public double XmlSerializationOnly_InT
    {
        get { return InT; }
        set { SetInT(value); }
    }
}

This works, it's easy enough to do, and the XML file looks like you'd expect. It's manual labour though, and a bit ugly, so I'm only somewhat satisfied. What I'd really like is to be able to tell the XML serialization to read the value using the property, and set it using the setter function. Then I wouldn't need XmlSerializationOnly_InT at all.

I seem to be following standard practise by distinguishing between property sets and setter functions in this way, so I'm sure I'm not the only person to have encountered this (though google suggests I might be). What have others done in this situation? Is there some easy way to persuade the XmlSerializer to handle this sort of thing better? If not, is there perhaps some other easy way to do it?

+1  A: 

EDIT:
I would really just make the setter function part of the property. If you want you could have the setter trigger an event and call the function in the event.

// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);

class X
{
    private double _inT;

    // An event that clients can use to be notified whenever the
    // elements of the list change.
    public event ChangedEventHandler InTChanged;
    // Invoke the Changed event; called whenever list changes

    protected virtual void OnChanged(EventArgs e) 
    {
        if (InTChanged != null)
            InTChanged(this, e);
    }
    public double InT
    {
        get { return InT; }
        set
        {
            _inT = newInT;

            //Invoke InTChanged event here
            OnChanged(EventArgs.Empty);
        }
    }
}

Otherwise you could just right your own serialize and deserialize functions:

class X
{
    public void SetInT(double newInT)
    {
        if (newInT != _inT)
        {
            _inT = newInT;
            Changed();//includes delegate call; potentially expensive
        }
    }

    private double _inT;

    public double InT
    {
        get { return InT; }
    }
    public XElement SerializeX()
    {
        XElement serializedItems = new XElement("X",
            new XElement("InT", this._inT),
            new XElement("OtherProperty1", this.OtherProperty1),
            new XElement("OtherProperty2", this.OtherProperty2));
        return serializedItems;
    }
    public void DeserializeX(XElement itemXML)
    {
        this._inT = Double.Parse(itemXML.Element("InT").Value,
            CultureInfo.InvariantCulture);
        this.OtherProperty1 = Double.Parse(
            itemXML.Element("OtherProperty1").Value,
            CultureInfo.InvariantCulture);
        this.OtherProperty2 = Double.Parse(
            itemXML.Element("OtherProperty2").Value,
            CultureInfo.InvariantCulture);
    }
}
smoore
Doesn't this change the behavior of the code? You could accidentally can `x.InT = someDouble` elsewhere and lose the call to Changed().
Austin Salonen
Yeah, the name is just to stop people using it! I don't really want the XmlSerializationOnly_InT property at all. It's only there to give the serializer something that it can work with. Ideally, there's just be the read-only property InT, and the setter method SetInT.
brone
@brone-Could you have the setter trigger an event and have an event handler reside somewhere else that calls your Changed() function? Many properties are done that way, and it doesn't look like it would go against any of the design practices you posted above.
smoore