Archive

Posts Tagged ‘serialization’

It’s Optional

April 19th, 2009 Comments off

What’s the best way to store and retrieve optional settings or preferences for users for your C# application? For simple stuff, there’s no easier way than creating settings in Visual Studio:

Settings dialog

Note that you can use settings for both simple values like bool and string, and for more complex values like colors.

These settings get persisted in a file called [your program name].exe.config.

And you can refer to them in code like this:

    private void GetBackgroundColor()
   {
         this.BackColor = Properties.Settings.Default.BackgroundColor;
    }
 
    private void SetBackgroundColor(Color backcolor)
    {
          Properties.Settings.Default.BackgroundColor = backcolor;
          Properties.Settings.Default.Save();
    }

Well, that’s all very well, simple, and very useful. But it gets messy if you want to set up a lot of options and particularly if you need options using your own enums, in various categories or for different states or objects in your application – the Settings dialog is just a very simple, line by line set of options with no structure.

My own preference* is to create one or more Options classes, and to use the nifty Xml Serialization stuff which I talked about previously on this blog to load and save the class.

Here’s a considerably cut-down version of my Options class from my software Chapter Master:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Options
{
	public enum ImageGrabOptions
	{
	    None,
	    CropFromTop,
	    CropFromLeft,
	    CropFromRight,
	    CropFromBottom,
	    CropFromCentre,
	    Pad
	}
 
	public enum SaveOptions
	{
	    None,
	    RenameOriginal,
	    PromptForNew
	}
 
	[System.Xml.Serialization.XmlElement()]
	public ImageGrabOptions ImageGrab = ImageGrabOptions.CropFromTop;
 
	[System.Xml.Serialization.XmlElement()]
	public SaveOptions SaveOption = SaveOptions.PromptForNew;
 
	[System.Xml.Serialization.XmlElement()]
	public int PadColorAsInt = Color.White.ToArgb();
 
	[System.Xml.Serialization.XmlIgnore]
	public Color PadColor
	{
	    get {
	        return Color.FromArgb(PadColorAsInt);
	        }
 
	    set {
	        PadColorAsInt = value.ToArgb();
	    }
	}
 
	public Options()
	{
	}
 
	public bool Save(string filename)
	{
	    return Seralize.ToXmlFile(filename, this);
	}
 
	public static Options Load(string filename)
	{
	    return opts = (Options) Seralize.FromXmlFile(filename, typeof(Options));
	}
}

Where Serialize is a class containing just the Xml serialization routines I wrote based on this Code Project article.

Note the way that the Color is serialized in lines 27-40, the same sort of workaround as is needed for TimeSpan values.

I like this approach because among other things, it allows different sets of preferences to saved and loaded as required.

Accessing these option values is very simple (this code is a fudge written just to demonstrate my general approach):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private readonly string MySettingsFolder = 
      System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
      + @"\ProgramName";
 
private OptionClass MyOptions;
 
private void GetOptions()
{
     MyOptions = Options.Load(MySettingsFolder  + @"\Default Options.xml");
}
 
//....and thus code like:
 
picCover.BackColor = MyOptions.PadColor;
if (MyOptions.ImageGrab.CropFromBottom)
{
     //........
}
 
private bool SaveSpecialOptions()
{
    return MyOptions.Save(MySettingsFolder  + @"\Special Options.xml");
}

* I’m happy to have others tell me why there are better ways. As always, I certainly don’t claim to be any kind of expert. This is just the way I like to do it. If you think it’s dumb, tell me so.

Categories: Programming Tags: , , ,

In praise of XML serialization

March 18th, 2009 Comments off

I know that Jeff Atwood over at Coding Horror isn’t very fond of XML, but personally, I have grown to love it. Well, not XML as such, but the ease of serializing and de-serializing C# classes to XML and back provided by Visual Studio.

Jeff’s complaints seem to be all about the difficulty that humans (well, programmers, anyway) have in reading all those angle brackets. To me, this seems to be beside the point, since humans aren’t really supposed to be reading XML anyway – computers are. It’s just a nice side-benefit that we programmers can look at XML files with a text editor and generally get a pretty good sense of what is going on.

Anyway, what I love about serializing to XML is the way that in C# you can build up a very complex object, with nested lists of diverse objects and such, and yet just blatt it all out to a file, or send it by MSMQ, and just magically read it back and have that fully complex object back again, without any need to spend time coding to parse it all in or out.

For example, in one of the applications I built for Kaleidio, we are simulating electronic transactions between companies. So I have a class called ‘Company’, name, address, etc, as you would expect it; but among other complexities, the company class also includes an array of storage locations. Each storage location has a list of products being stored, each with its own information about price, unit size, bar-code, etc. Obviously, these are ‘toy’ companies with far less complexity than the real thing; but nevertheless, they are complex objects.

With serialization, I can just set up and save an entire company object to disk, or pick it up and despatch it to another computer via MSMQ (or SOAP, or whatever).

There’s a great article with some really good utility routines for reading and writing serialized XML here at Code Project. If you base your code on these routines, you can write code like this:

	var myCompany = new Company();
 
	//fill in company details, add storage locations, 
	//fill locations with products, etc.
 
	ToXMLfile(@"C:\temp\company.xml", myCompany);
 
	//then, later:
 
	var loadedCompany = (Company)FromXMLfile(@"C:\temp\company.xml", 
						typeof(Company);
 
	//now work with the company again.

To make this all work well you generally have to assign attributes to members of your classes to give the serializer hints as to how you want the XML to work.

	public class Company
	{
		[System.Xml.Serialization.XmlAttribute()]
		public string Name = "MyBusiness";
 
		[System.Xml.Serialization.XmlElement()]
		public string Address= "41 Smith Street, Collingwood, Vic 3066";
	//....

This creates XML like:

	<Company Name="MyBusiness">
	<Address>41 Smith Street, Collingwood, Vic 3066</Address>
		....
	</Company>

 
I have used this a lot in the last 6 or 7 years, but I have to admit that it’s a feature of Visual Studio that I have basically taken for granted, and only rarely had to worry about the implementation. In other words, I haven’t really researched it and thought about it in any detail, just used it at a basic level. I’m guessing that most practicing programmers use many such language features in the same way.

But it’s when what you have taken for granted suddenly causes you grief that you have to start hitting the F1 key (or, more usefully, googling) to get some answers.

For example, there are some kinds of data type which you can’t serialize directly, such as TimeSpan. So you have to use a workaround like this:

        [System.Xml.Serialization.XmlElement]
        public long DurationTicks;
 
        [System.Xml.Serialization.XmlIgnore]
        public TimeSpan Duration
        {
            get { return new TimeSpan(DurationTicks); }
            set
            {
                DurationTicks = value.Ticks;
            }
        }

Note that one of the disadvantages of serialization is that any value to be serialized must be marked as public, so DurationTicks above is visible as a member of the class to which it belongs, even though you don’t really want it messed with directly.

Where I have gotten myself into difficulties in the past is where you want a class to be able to have a member which may be of various different kinds of object. They are different, but they do all inherit from a base class.

You can use a construct like this, which uses an additional class member to indicate to the serializer the type of object being included:

        [System.Xml.Serialization.XmlChoiceIdentifier("ControlType")]
        [System.Xml.Serialization.XmlElement(Type = typeof(VideoControl))]
        [System.Xml.Serialization.XmlElement(Type = typeof(ImageControl))]
        [System.Xml.Serialization.XmlElement(Type = typeof(FlashControl))]
 
        public Control ControlObj = null;
 
        /// <summary>
        /// Identifies the type of control being sent.
        /// </summary>
        [System.Xml.Serialization.XmlIgnore]
        public ControlTypes ControlType = ControlTypes.None;

Note the XmlIgnore tag, which tells the serializer not to explictly include this property in the XML.

But I struggled for a while to figure out what to do when the class I was trying to serialize had a member which was a list of such variable objects.

For example in one of my shareware projects, I have an object which includes such a list (a List<FileRecord>, to be specific). Mostly this list contains plain FileRecord objects, but I also have a class called CDTrackRecord which inherits from FileRecord. For quite a while I couldn’t figure out how to correctly serialize a class with a list which included one or more such inherited objects.

I’m still not sure if this is the best solution, but I discovered that you can use an XmlInclude attribute on the base class of list members, like this, to show it also includes the possibility of the inherited object:

        [System.Xml.Serialization.XmlInclude(typeof(CDTrackRecord))]
        public class FileRecord
        {
                //class members
        }

The class including a List<FileRecord> now serializes nicely.

Disclaimer: I don’t claim to be any kind of programming expert, just a dumb old programmer with a passion for coding. Bear this in mind if you comment!

Categories: Programming Tags: , ,
Performance Optimization WordPress Plugins by W3 EDGE