Geeks With Blogs
Tex-blog Mobile and other stuff

While writing practice programs for my 70-536 exam I encountered interesting problem of writing custom IFormatter implementation. .NET offers many classes that can fit most of ours serialization tasks, yet sometimes it might happen that we would like to do something differently. As I was looking for sample implementation of this interface, I noticed that there was very little about it in internet. One of the most interesting articles was "Run-time Serialization" by Jeffrey Richter found in april 2002 MSDN Magazine (http://msdn.microsoft.com/msdnmag/issues/02/04/net/). It does not talk much about custom IFormatter implementetion but gives good explanation of FormatterServices class - which is very useful for this task.

Below is simple example of how to implement custom formatter class, its purpose is to serialize any class's fields to well known ini file format. All fields will be stored in text file in a form of a "variableName=variableValue" pairs. Since this is just a practice class I wrote for the end of chapter 5 from 70-536 training kit it was not very well tested and also does not provide all the functionality that a production code should provide:


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Reflection;
using System.IO;
using System.Collections.Specialized;

namespace Practice {
    class SimpleIniFormatter : IFormatter {
        SerializationBinder binder;
        StreamingContext context;
        ISurrogateSelector surrogateSelector;

        public SimpleIniFormatter() {
            context = new StreamingContext(StreamingContextStates.All);
        }       

        public object Deserialize(System.IO.Stream serializationStream) {
            StreamReader sr = new StreamReader(serializationStream);
            
            // Get Type from serialized data.
            string line = sr.ReadLine();
            char[] delim = new char[] { '=' };
            string[] sarr = line.Split(delim);
            string className = sarr[1];
            Type t = Type.GetType(className);

            // Create object of just found type name.
            Object obj = FormatterServices.GetUninitializedObject(t);

            // Get type members.
            MemberInfo[] members = FormatterServices.GetSerializableMembers(obj.GetType(), Context);

            // Create data array for each member.
            object[] data = new object[members.Length];

            // Store serialized variable name -> value pairs.
            StringDictionary sdict = new StringDictionary();    
            while (sr.Peek() >= 0)  {
                line = sr.ReadLine();
                sarr = line.Split(delim);
                
                // key = variable name, value = variable value.
                sdict[sarr[0].Trim()] = sarr[1].Trim();
            }
            sr.Close();

            // Store for each member its value, converted from string to its type.
            for(int i = 0; i < members.Length; ++i )  {
                FieldInfo fi = ((FieldInfo)members[i]);
                if (!sdict.ContainsKey(fi.Name))
                    throw new SerializationException("Missing field value : " + fi.Name);
                data[i] = System.Convert.ChangeType(sdict[fi.Name], fi.FieldType);
            }            

            // Populate object members with theri values and return object.
            return FormatterServices.PopulateObjectMembers(obj, members, data);
        }

        public void Serialize(System.IO.Stream serializationStream, object graph) {
            // Get fields that are to be serialized.
            MemberInfo[] members = FormatterServices.GetSerializableMembers(graph.GetType(), Context);

            // Get fields data.
            object[] objs = FormatterServices.GetObjectData(graph, members);

            // Write class name and all fields & values to file
            StreamWriter sw = new StreamWriter(serializationStream);
            sw.WriteLine("@ClassName={0}", graph.GetType().FullName);
            for (int i = 0; i < objs.Length; ++i) {
                sw.WriteLine("{0}={1}", members[i].Name, objs[i].ToString());
            }
            sw.Close();
        }

        public ISurrogateSelector SurrogateSelector {
            get { return surrogateSelector; }
            set { surrogateSelector = value; }
        }
        public SerializationBinder Binder {
            get { return binder; }
            set { binder = value; }
        }
        public StreamingContext Context {
            get { return context; }
            set { context = value; }
        }
    }
}

Posted on Monday, July 16, 2007 3:32 AM 70-536 preparation | Back to top


Comments on this post: Writing simple custom formatter - implementation of IFormatter intereface

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Hi !

Good example of using the IFormatter.
I agree that there aren't much articles on it. Got to your page since I myself now am preparing for the 70-536 exam.
Left by Micke on Sep 03, 2007 2:06 PM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Hi,
this is a really useful article for all of them out there preparing for 70-536. Microsoft does not provide any Example.
I tried using .Net Reflector from Lutz Roeder to take a closer look at the implementation of the BinaryFormatter - but too much code and less time. Your post is really good for the basic understanding of the IFormatter Interface.
I will try now to implement a EncryptedFormatter.
Thank you really much !
Left by Ilija Injac on Feb 01, 2008 2:49 PM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Yeah, this is what I was looking for! Now I need to write my own formatter and this article saves me at least one day if no more, thanks.
Left by Viktor on Feb 29, 2008 6:41 AM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
What about recursion? what if one of the field is a non premitive type?
Left by Tehila on Aug 02, 2009 2:09 AM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
thanks...realy its so simple to understand custom serialization...
Left by vinita on Jan 06, 2010 10:43 AM

# Oversimplified Implementation
Requesting Gravatar...
As Tehila pointed out this is a very bad example for anything more than types containing only primitive types. Any encounter with only the slightest complex class (ie one containing a reference to another class) will cause your formatter to fail.

The correct approach would be to recursively serialize any types that weren't a primitive type.
Left by Qua on Apr 08, 2010 10:22 AM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Come on people give the guy a break, this is a simple answer to a textbook excerise, if you wanted to extend it to cover non-primitive types using recursion (or non recursion) I am sure you could all do that!
Left by Duckers on May 31, 2010 7:50 AM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Nice work man. I was looking for this all over.
Left by measow on Dec 03, 2010 12:24 PM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Perfect example, many thanks for this, I've been hunting high and low for an example of custom serialization to a custom formatted text file.
Left by Neil on Feb 01, 2011 11:12 PM

# re: Writing simple custom formatter - implementation of IFormatter intereface
Requesting Gravatar...
Minor niggle, but the line
sw.Close();
also closes the stream. For behaviour that mimics the BinaryFormatter class, the line ought to be
sw.Flush();

Similarly, the line
sr.Close();
should be
sr.Dispose(); // Or use a 'using' clause.

-- Tim
Left by Tim Williams on Feb 05, 2013 10:05 PM

Your comment:
 (will show your gravatar)


Copyright © Martinez | Powered by: GeeksWithBlogs.net