Roadmap

Coordinator
Nov 4, 2010 at 9:29 PM
Edited Nov 4, 2010 at 9:45 PM

Where should "it" go from where it is now? The origin of the idea is as it states on home page - cease pain of using System.Xml.XmlSerializer.

We want to be able to:

  • serialize object that contain properties of abstract types and interface types
  • do not include domain and CLR specific metadata within XML (for example class names, assembly qualifiers and sort...)
  • do not include XML specific metadata within domain
  • be as fast as it is possible
  • allow to configure mapping strategies but provide default strategies also
  • be dependency injection friendly
  • allow to (de)serialize values/instances at least in two ways - tree way, and string way
  • if we allow two ways of values/instances (de)serialization, lets assume, that more will show up - make it a matter of strategy or convention choice

What if we have this kind of domain?

public interface IPet 
{
public string Name { get; }
}

public class Owner
{
public IPet Pet { get; set; }
}

public class Keeper
{
public IList<IPet> Pets { get; private set; }
public Keeper()
{
Pets = new List<IPet>();
}
}

public class Cat : IPet
{
public string Name { get; private set; }
public Cat(string name)
{
Name = name;
}
}

public class Dog : IPet
{
public string Name { get; set; } 
  public double KilosPerUnitJawForce { get; set; } } public class Cage<T> where T : IPet { public int Width { get; set; } public int Height { get; set; } public IPet CurrentPet { get; /*pet; oops, sorry*/ set; } }

There are some challenges that come to one's mind, when looking at this - yet simple - domain (sorry for animals again, but I couldn't make up anything more... ummm... natural?).

Read only properties

If we want to serialize readonly properties, we need/would like to allow some means of setting them back when deserializing. One (most obvious) way is to use constructor with some convention over property-to-constructor-parameter matching (similar to the one used by Castle Windsor when defining components in Xml).

That leads to some consequences, including introducing two natural phases of deserialization - construction and buildup.

Some funny scenarios may appear here - such as the one, where we don't have match. Then:

  • should we ignore readonly property when serializing, because we don't know how to deserialize it?
  • should we allow to separate serialization strategy from deserialization strategy?

Dependency injection

If we want to mock with constructors, we have 2 paths to follow here:

  • create abstraction for constructor related logic and force users to create custom DI engine extensions, that would serve mediator role between Pinky and DI
  • take responsibility for constructing objects to Pinky side, which would use DI to provide some extra data. For example - provide object instances, for constructor parameters that are not related with XML model.

Generics

Generics are crap sometimes, crap that is parallel to inheritance, but without language support in some cases. Thats why they can be pain in the arse, when talking about type mapping - if we wish to map generic type and generic parameters independently, we need mapping that is smarter than IDictionary<string, Type>.

We end up with two possibilities:

  • Ignore them - make each closed generic act as whole type, which is easy to implement, but pain to live with. See note below.
  • Create smart mapper - should not be that difficult, and opens bright possibilities for generics zealots.

Note: My personal opinion is that generics are often overused and made to close to "facade" than they should be, especially when System.Type becomes domain entity ;F.

Circular object graphs, relations

The question is, if we really want Pinky to be relational graph aware. I think not. But circular referencing is some of the things, that forces us to make it at least a little bit aware ...

Smelly examples

Let's make pets - almost like in "Porno for pyros" song.

var cat = new Cat("Kitty");
var dog = new Dog() { Name = "Cezary", KilosPerUnitJawForce = 30 }

.. and let's froze them into some taggy shape? (note: no pets were actually harmed during serialization process).

<Cat>
    <Name>Kitty</Name>
</Cat>

<Dog>
    <Name>Cezary</Name>
    <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
</Dog>

 

Root tag (As it is in case of standard XmlSerializer If I am correct) takes its name from class name, and it would be nice to have possibility to setup some kind of mapping between Type and this name. From the other hand, inner tags are named after property names, where mapping between PropertyInfo and tag name is of course desired. But flat structures are boring, so lets give those orphans some owners:

 

var catOwner = new Owner() { Pet = cat };
var dogOwner = new Owner() { Pet = dog };

 

And now we can have this representation:

 

<Owner>    
    <Pet type="Cat">
        <Name>Kitty</Name>
    </Pet>
</Owner>

<Owner>
    <Pet type="Dog">
        <Name>Cezary</Name>
        <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
    </Pet>
</Owner>

Note "type" attribute, where I used the same values as when I "serialized" pets into independent nodes.

In the examples above, Xml model is mapped to CLR model in a simple manner. In real life, it would be nice to have more options than name-to-name mapping. Some weird-xml-with-500-levels-of-nesting-to-System.DateTime mapping should also be made possible :-)

Conclusion

When we start thinking about configuration and extensibility the differences will become more visible. It is not possible to use this domain with XmlSerializer out-of-the box, but it can be hacked to do so. But we don't want hacks, which have limited power and are the edge of possibilities sometimes, where we want to have those possibilities commonly accessible.

Community.Discuss();

 

Coordinator
Nov 5, 2010 at 6:17 PM
Edited Nov 5, 2010 at 6:18 PM

One thought after Friday adventures with "regular job": root tag names should not work, like I stated above - root tag names should be specified by user when serializing or set to some default value (Anonymous suits this case perfectly). So instead of this:

 

<Cat>
    <Name>Kitty</Name>
</Cat>

<Dog>
    <Name>Cezary</Name>
    <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
</Dog>

<Owner>    
    <Pet type="Cat">
        <Name>Kitty</Name>
    </Pet>
</Owner>

<Owner>
    <Pet type="Dog">
        <Name>Cezary</Name>
        <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
    </Pet>
</Owner>

 

we would have this:

 

<Anonymous type="Cat">
    <Name>Kitty</Name>
</Anonymous>

<Anonymous type="Dog">
    <Name>Cezary</Name>
    <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
</Anonymous>

<Anonymous type="Owner">    
    <Pet type="Cat">
        <Name>Kitty</Name>
    </Pet>
</Anonymous>

<Anonymous type="Owner">
    <Pet type="Dog">
        <Name>Cezary</Name>
        <KilosPerUnitJawForce>30</KilosPerUnitJawForce>
    </Pet>
</Anonymous>