views:

169

answers:

4

Does anyone know of a quick and dirty implementation of a reflection based XML serializer?

I am looking to rip out my XML serialization code due to the horrid start up time. I know about sgen.exe but do not want to complicate my build and packaging process.

We use the XML serialization at startup to pull out configuration values from a file, the reflection hit would be minimal, we are talking 20-40 values max. We do not need anything super fast here. I just do not want to take the hit for compiling the XML serializer that seems to be 500-700ms in my case.

I also would like control of the code, cause I would like very robust error handling.

I know about protobuf.net, but it may be a bit of an overkill. Looking at data contracts they may be a tad limited and require quite a lot of decoration I would like to avoid.

+1  A: 

Have you tried pre-compiling the serializers using sgen?

http://blog.lab49.com/archives/2358

Simon
sorry really do not mean to sound rude, but sgen is completely out of the question.
Sam Saffron
+1  A: 

If you use sgen.exe with the /k[eep] option, it will keep the generated C# source that you can then integrate into your project. You can customize it as you see fit.

EDIT: In other words, you're using sgen not as a pre-compiler (which you say you can't do), but as a code-generator.

pyrochild
+3  A: 

If it's just 20 to 40 values, why not throw away all the serialisation malarkey and hand code it? You should be able to code a settings reading class in no time flat. Heck, you could code generate it and go home early. That way it can be as robust and error handled as you like, and it'll be shedloads faster than 700ms.

Dan F
I agree. If you're at all concerned with execution speed, using reflection seems like a poor path to take.
overslacked
reflection is not such a big hit in my case, its taking me 63 ms to load the dom (forward parsing is a much faster route... but probably not worth the effort) and 17 ms to load my fields with reflection and I am not done optimising.
Sam Saffron
+1  A: 

I wrote my own... feel free to use it if anyone has similar specs the code it under the BSD license.

Here are some sample tests, it generates lovely XML just like the XML serializer only much faster for config file scenarios where sgen is not an option:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NUnit.Framework;
using MediaBrowser.Library.Persistance;

namespace TestMediaBrowser.Unit {
    [TestFixture]
    public class TestXmlSettings {

        enum Farts { 
            Smelly, 
            SilentButDeadly
        }

        class Monster {
            public Weapon Weapon; 
        }

        class Weapon {
            public int LaserCount { get; set; }
        }

        class Farter {
            public Farts Smell = Farts.Smelly;
        }

        class Group {
            public List<Person> People;
        }

        class Person {
            public int Age = 1; 
            public string Name = "Default";
            public bool Happy = true;
            public DateTime Birthdate = DateTime.Now;  
        }

        class Account {
            public Person Person;
            public int Balance;
        }

        const string CONFIG_FILE = "test.config";

        private void ClearConfig() {
            if (File.Exists(CONFIG_FILE)) {
                File.Delete(CONFIG_FILE);
            }
        }

        public void TestProperty() {
            ClearConfig();
            Monster monster = new Monster();
            XmlSettings<Monster> settings = XmlSettings<Monster>.Bind(monster, CONFIG_FILE);
            monster.Weapon = new Weapon();
            monster.Weapon.LaserCount = 99;
            settings.Write();

            monster = new Monster();
            settings = XmlSettings<Monster>.Bind(monster, CONFIG_FILE);

            Assert.AreEqual(monster.Weapon.LaserCount, 99);
        } 

        public void TestEnum() {
            ClearConfig();
            Farter farter = new Farter();
            XmlSettings<Farter> settings = XmlSettings<Farter>.Bind(farter, CONFIG_FILE);
            farter.Smell = Farts.SilentButDeadly;
            settings.Write();

            farter = new Farter();
            settings = XmlSettings<Farter>.Bind(farter, CONFIG_FILE);

            Assert.AreEqual(farter.Smell, Farts.SilentButDeadly);
        } 

        [Test]
        public void TestList() {
            ClearConfig();
            Group group = new Group();
            group.People = new List<Person>();
            group.People.Add(new Person());
            group.People.Add(new Person());
            XmlSettings<Group> settings = XmlSettings<Group>.Bind(group, CONFIG_FILE);
            settings.Write();

            group = new Group();
            settings = XmlSettings<Group>.Bind(group, CONFIG_FILE);

            Assert.AreEqual(group.People.Count, 2);

        }

        [Test]
        public void BasicValueTypeTest() {
            ClearConfig();
            var person = new Person();
            XmlSettings<Person> settings = XmlSettings<Person>.Bind(person, CONFIG_FILE);
            person.Age = 3;
            person.Name = "Sam";
            person.Happy = false;
            person.Birthdate = DateTime.Today;
            settings.Write();

            person = new Person();
            settings = XmlSettings<Person>.Bind(person, CONFIG_FILE);

            Assert.AreEqual(person.Age, 3);
            Assert.AreEqual(person.Name, "Sam");
            Assert.AreEqual(person.Happy, false);
            Assert.AreEqual(person.Birthdate, DateTime.Today);
        }

        [Test]
        public void NestedObjectTypeTest() {
            ClearConfig();
            var account = new Account();
            var settings = XmlSettings<Account>.Bind(account, CONFIG_FILE);
            var person = new Person();
            person.Age = 3;
            person.Name = "Sam";
            person.Happy = false;
            person.Birthdate = DateTime.Today;

            account.Person = person;
            account.Balance = 999;

            settings.Write();

            account = new Account();
            settings = XmlSettings<Account>.Bind(account, CONFIG_FILE);


            person = account.Person;
            Assert.AreEqual(account.Balance, 999);
            Assert.AreEqual(person.Age, 3);
            Assert.AreEqual(person.Name, "Sam"); 
            Assert.AreEqual(person.Happy, false); 
            Assert.AreEqual(person.Birthdate, DateTime.Today); 
        }
    }
}
Sam Saffron