How to handle type references (not parent/child)

Dec 20, 2012 at 7:26 PM
Edited Dec 20, 2012 at 7:28 PM

Hi, we came across this library today and really like the breadth of features and the API it has. However, we're not sure how to accomplish serializing and deserializing a certain object model into the format that we'd like to see.

Basically, we have an object graph like this:

public class MeasurementUnit
{
    public string Name { get; set;}
}

public class MeasurementType
{
    public string Name { get; set; }
    public MeasurementUnit BaseUnit { get; set; }
    public IEnumerable<MeasurementUnit> AvailableUnits { get; set;}
}

public class SensorType
{
    public string Name { get; set; }
    public double MinValue { get; set; }
    public double MaxValue { get; set; }
    public MeasurementType MeasurementType { get; set;}
    public MeasurementUnit DisplayUnit { get; set; }
}

public class Settings
{
    public IEnumerable<SensorType> SensorTypes { get; set; }
    public IEnumerable<MeasurementType> MeasurementTypes { get; set; }
    public IEnumerable<MeasurementUnit> MeasurementUnits { get; set; }
}

 

And the XML format we'd like to end up with is this:

<Settings>
    <SensorTypes>
        <SensorType Name="Sensor1" MinValue="0" MaxValue="100" MeasurementType="Pressure" DisplayUnit="KPA" />
        <SensorType Name="Sensor2" MinValue="32" MaxValue="212" MeasurementType="Temperature" DisplayUnit="F" />
    <SensorTypes>
    <MeasurementTypes>
        <MeasurementType Name="Pressure" BaseUnit="PSI">
            <AvailableUnits>
               <MeasurementUnit Name="PSI" />
               <MeasurementUnit Name="KPA" />
               <MeasurementUnit Name="MPA" />
            </AvailableUnits>
        </MeasurementType>
        <MeasurementType Name="Temperature" BaseUnit="F">
            <AvailableUnits>
               <MeasurementUnit Name="F" />
               <MeasurementUnit Name="C" />
            </AvailableUnits>
        </MeasurementType>
    </MeasurementTypes>
    <MeasurementUnits>
        <MeasurementUnit Name="PSI" />
        <MeasurementUnit Name="KPA" />
        <MeasurementUnit Name="MPA" />
        <MeasurementUnit Name="F" />
        <MeasurementUnit Name="C" />
    </MeasurementUnits>
</Settings>

So basically the references to other objects (like the MeasurementType property of a SensorType object) we want to store as just an attribute with an identifier (in this case the Name property, but it could be an Id too).

That part we figured out how to do. What we don't know how to do is the deserialization. For example, when a SensorType object is deserialized, we want it's MeasurementType property value to be referencing the corresponding MeasurementType object that will be deserialized into the MeasurementTypes property of Settings. In other words, it needs to be a reference to that object in the collection, not another new instance of a MeasurementType.

Hopefully that makes sense. Is this type of thing possible to do with YAXLib?

Thanks!
Kevin Kuebler 

Coordinator
Dec 23, 2012 at 2:24 AM

Hi Kevin,

I'm afraid this kind of functionality is not possible at the moment. Even if it was, I don't know how identical references could be represented in the XML output.

Maybe using an enum instead of an object could do the trick for you, but possibly it would change your object model in an unpleasant way. Sorry!

Regards,
Sina

Apr 17, 2013 at 2:52 PM
Hi all,

I've accomplished what Kevin wants.

I've implemented two ICustomSerializers:
class CollectionReferenceSerializer<T> : ICustomSerializer<T> { }

class ReferenceSerializer<T> : ICustomSerializer<T> { }
and I decorate the members of a class with these, like in the example below.
class LayoutEntry
{
    [YAXLib.YAXCustomSerializer(typeof(ReferenceSerializer<Hoth.DataModel.Entry>))]
    public Entry MyEntry { get; set; }
    [YAXLib.YAXCustomSerializer(typeof(CollectionReferenceSerializer<List<LayoutEntry>>))]
    public List<LayoutEntry> Children { get; set; }
}
Serialization on these custom serializers is made like Kevin mentioned. Only an ID is stored within that instance on the XML.
Deserialization creates new instances with only the ID filled in (because that is only what it is at the XML).
The implementation of these custom serializers is fairly simple. Assume an attribute called ID of type GUID and output just that to the XML.

Now the part that is missing to Kelvin.

My example class LayoutEntry also implements a method ResolveReferences(IList<LayoutEntry> AllEntries) that is called after all de-serialization takes place. This method goes through all LayoutEntry in the Children collection and replaces those instances with the corresponding (using the ID) at the AllEntries collection provided. This AllEntries collection is the only place where LayoutEntrys are fully serialized!
And basically that’s it!

In my case I’m dealing with a data model classes, so all share a common inheritance providing the ID and the ResolveReferences() as a basis.
Also, I provide to ResolveReferences() my all data state instance that holds all items collections and the implementation uses what it needs.
Because of this speciality I don’t think the all problem can be solved easily by YAXLib. But a class attribute (applied to members) that instructed the serialization (on that instance) of only one specified ID field would be nice (that is, basically the procedure of two custom serializers above).

See you.
ztp