Click here to Skip to main content
15,878,814 members
Articles / Programming Languages / C#
Tip/Trick

Serializing Interfaces to a File

Rate me:
Please Sign up or sign in to vote.
4.64/5 (4 votes)
31 Dec 2017CPOL1 min read 8.9K   88   7   2
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:

C#
/// <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:

C#
/// <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:

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer
Norway Norway
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMemory leaks Pin
Stacy Dudovitz1-Jan-18 12:35
professionalStacy Dudovitz1-Jan-18 12:35 
AnswerRe: Memory leaks Pin
Kenneth Haugland1-Jan-18 19:18
mvaKenneth Haugland1-Jan-18 19:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.