ExtendedXmlSerializer/home

Delegate instantiation of interfaces

Closed this issue ยท 4 comments

As far as I understood ExtendedXmlSerializer de/serializes interface properties by emitting/reading the actual implementation type from/to an xmlattribute. I don't want this behaviour because I want the implementing types to be independent on both sides of the wire. That means they implement the same interface but are not related otherwise. Instead I would rather like to instruct ExtendedXmlSerializer to use a factory supplied by me that knows about instatiating interface instances. Something like the following pseudocode:

public interface IDomainObject
{
    // interface members ...
}
public interface IDomainObjectFactory
{
    T Create<T>();
    object Create(System.Type interfaceType);
}

Then I would like to configure the serializer in the following way:

IExtendedXmlSerializer serializer = new ConfigurationContainer().Type<IDomainObject>()
    .InstantiateWith(() => new DomainObjectFactory().Create<IDomainObject>()) // unfortunately there is no such method
    .Create();

My question is whether there is any advice how I could implement something like that. Or any pointers at all where to look if I want to completly customize object instantiation.

Issue-Label Bot is automatically applying the label enhancement to this issue, with a confidence of 0.80. Please mark this comment with ๐Ÿ‘ or ๐Ÿ‘Ž to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

Wow that is an interesting and powerful scenario, @taxophobia! Thank you for writing in and asking about it.

For some context with ExtendedXmlSerializer, it was primarily meant for application state, for games, or really other applications that needed some internal memory easily stored as an object graph in the XML format and then at some later point easily read back into memory. Data exchange over the wire while (hopefully ๐Ÿ˜) supported was not a focus.

So with that stated, we might be able to achieve what you're looking for via custom serializer. It's not perfect as you would have to apply it on a type-by-type basis, but it's a starting point that we could explore.

I have created a basic prototype/example for you to check out here:

[Fact]
public void Verify()
{
var container = new ConfigurationContainer().Type<IInterface>()
.Register()
.Serializer()
.Using(Serializer.Default)
.Create()
.ForTesting();
var instance = new Container {Interface = new Implementation()};
container.Cycle(instance)
.Interface.Should()
.BeOfType<Implementation>()
.And.Subject.To<Implementation>()
.Created.Should()
.BeTrue();
}
sealed class Container
{
public IInterface Interface { get; set; }
}
sealed class Serializer : ISerializer<IInterface>
{
public static Serializer Default { get; } = new Serializer();
Serializer() {}
public IInterface Get(IFormatReader parameter)
{
var name = parameter.Content();
var type = Type.GetType(name) ?? throw new InvalidOperationException($"Could not parse '{name}'");
var result = (Implementation)Activator.CreateInstance(type);
result.Created = true;
return result;
}
public void Write(IFormatWriter writer, IInterface instance)
{
writer.Content(instance.GetType().AssemblyQualifiedName);
}
}
public interface IInterface {}
public sealed class Implementation : IInterface
{
public bool Created { get; set; }
}

Essentially, when an interface-type gets written, the full type name is written out. And when it's read back in, the type is fetched via the written inner-content and activated. You could replace that with a call to your IDomainObjectFactory.Create.

Again, not perfect, but a starting point we could further explore. Please let me know how all of this sits with you and we can take it from there. ๐Ÿ‘

Thank you very much for the example. It works for the usecase of serializing/deserializing a single instance without nested properties. For nested properties I think i should be able to adopt the example of the AnswerToEverything extension from the wiki. Basically doing the instantiation and then relying on the default serializer to handle the properties. I will tinker a bit more and post code or more questions later.

Cool... good to hear you found a direction, @taxophobia. A new release was posted to NuGet today so going through the issues here. Sounds like this is sufficiently resolved for now. If you do find that you have another question around this issue please do post a comment and I will re-open to further explore it with you. Closing for now.