Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Serializing Interfaces to a File

0.00/5 (No votes)
31 Dec 2017 1  
How to serialize and deserialize implemented interfaces to a file

Introduction

Recently, I have started to look into implementing Inversion of control (IoC) using the Unity framework from Microsoft's patterns and practices. The general IoC is by arranging implementation of classes that is implemented indirectly by using interfaces. This means that if you choose to apply your setting to the registered interface and want to save this for later, it is very practical to be able to serialize the interface. However, this is not implemented out of the box by the .NET Framework.

There is one thing that is a big advantage, and that is that the interfaces are implemented by known types, so all we need to do is grab the types and values that are implemented by the class and save these to a file.

The implementation with its limitations is described in this answer given here and this tip implements the serializer given and adds the deserializer into a project so that it is easily accessible to people. Also, fixed potential memory leak, see the comment below.

Code

The serializer is implemented as was given in the answer as follows:

/// <summary>
/// Creates an XElement from an implemented interface
/// </summary>
/// <param name="o">Object to be serialized</param>
/// <returns>An XElement from the implemented interface</returns>
/// <remarks>see https://stackoverflow.com/questions/1333864/
/// xml-serialization-of-interface-property for original implementation</remarks>
public static XElement Serialize(object ImplementedInterface)
{
    Type ObjectType = ImplementedInterface.GetType();

    Type[] ImplementedTypes = ObjectType.GetProperties()
           .Where(p => p.PropertyType.IsInterface)
           .Select(p => p.GetValue(ImplementedInterface, null).GetType())
           .ToArray();

    DataContractSerializer serializer = new DataContractSerializer(ObjectType, ImplementedTypes);
    using (StringWriter sw = new StringWriter())
    {
        using (XmlTextWriter xw = new XmlTextWriter(sw))
        {
            serializer.WriteObject(xw, ImplementedInterface);
            return XElement.Parse(sw.ToString());
        }
    }                                    
}

and the Deserializer is constructed using the same method:

/// <summary>
/// Creates an object from an interfaces saved in a XElement object
/// </summary>
/// <param name="File">XElement that should be turned into an object</param>
/// <param name="ImplementedInterface">Object that implemented the streamed interface</param>
/// <typeparam name="T">Represents the Interface you want the object casted to</typeparam>
/// <returns></returns>
public static T Deserialize<T>(XElement File, object implementedInterface) 
{
    Type ObjectType = implementedInterface.GetType();
    
    Type[] ImplementedTypes = ObjectType.GetProperties()
        .Where(p => p.PropertyType.IsInterface)
        .Select(p => p.GetValue(implementedInterface, null).GetType())
        .ToArray();
        
    DataContractSerializer serializer = new DataContractSerializer(ObjectType, ImplementedTypes);
    using (StringReader sr = new StringReader(File.ToString()))
    {
        using (XmlTextReader xr = new XmlTextReader(sr))
        {
            return (T)serializer.ReadObject(xr);
        }
    }                          
}

There are some shortcomings of this implementation, and this is if the implementation is of the type IList<IMyItems> or any other implementations where there are nested dependencies of other interface types. These issues can be solved by using reflection.

Usage

The serialization and deserialization can be implemented as:

ISettings MySettings;
// Create a object that implements the interface ISettings
MySettings = new Settings() { Name = "MyFile", ID = 2 };

// Serialize the interface
XElement XMLFile = InterfaceSerializer.Serialize(MySettings);

// You can save the XElement to file using this command:
// XMLFile.Save("SavedXMLFile.XML");

// Change stuff in the original stored value
MySettings.ID = 1;
MySettings.Name = "OldFile";

// Load a saved XElement by using this command:
// XMLFile = XElement.Load("SavedXMLFile.XML");

// Deserialize the object by using the XElement and the types implemented in the original Interface
ISettings OldSettings = InterfaceSerializer.Deserialize<ISettings>(XMLFile,MySettings);

Of all the possible ways to solve the serialization and deserialization of implemented interfaces, I found this method to be the easiest to use in my project.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here