Click here to Skip to main content
15,892,746 members
Articles / Desktop Programming / WPF

Converters class - Register all your data-type conversions in a single place

Rate me:
Please Sign up or sign in to vote.
4.96/5 (16 votes)
20 Sep 2012CPOL22 min read 39.2K   346   36  
This article explains how to create a class that can handle any kind of data-type conversion by allowing users to register their own conversions and how to make it work both as a global and also as a local solution, so different threads can do different conversions for the same data-types.
using System;
using System.Linq;
using System.Collections.Generic;
using ConfigurableConvertTest.GenericConverters;
using System.Diagnostics;

namespace ConfigurableConvertTest
{
    class Program
    {
        private const int COUNT = 10000000;
        static void Main(string[] args)
		{
			Converters.GlobalRegister<string, int>((value) => int.Parse(value));
			Converters.GlobalSearching += ToArrayConverter.SearchingConverterHandler;

			var converters = Converters.LocalInstance;

            // If you comment the next line, a converter from string to nullable will be
            // found thanks to the FromTypeDescriptorConverter. But such default converter
            // throws an exception if the string is filled with spaces.
            converters.Searching += StringToNullableConverter.SearchingConverterHandler;

            converters.Searching += FromTypeDescriptorConverter.SearchingConverterHandler;
			var converter = converters.Get<string, int>();
            if (converter("57") != 57)
				throw new Exception("Error to convert string to int.");

            if (GlobalConvert.ChangeType<string>(57) != "57")
                throw new Exception("Error on GlobalConvert.");

            converters.Searching += EnumToUnderlyingConverter.SearchingConverterHandler;
            converters.Searching += UnderlyingToEnumConverter.SearchingConverterHandler;

            using (var isolatedConverters = new Converters(ConvertersMode.Isolated))
            {
                if (isolatedConverters.TryGet<AttributeTargets, int>() != null)
                    throw new Exception("Isolated converters was not really isolated.");

                if (isolatedConverters.TryGet<string, int>() != null)
                    throw new Exception("Isolated converters was not really isolated.");
            }

            using (var basedOnGlobalConverters = new Converters(ConvertersMode.BasedOnGlobal))
            {
                if (basedOnGlobalConverters.TryGet<AttributeTargets, int>() != null)
                    throw new Exception("BasedOnGlobal converters found a previous local registered converter.");

                if (basedOnGlobalConverters.TryGet<string, int>() == null)
                    throw new Exception("BasedOnGlobal converters did not find a global registered converter.");
            }

            var enumToIntConverter = converters.Get<AttributeTargets, int>();
            int moduleAsInt = enumToIntConverter(AttributeTargets.Module);
			if (moduleAsInt != (int)AttributeTargets.Module)
				throw new Exception("Error converting an enum to its underlying type.");

            var stringToNullableIntConverter = converters.Get<string, int?>();
            if (stringToNullableIntConverter(" ").HasValue)
                throw new Exception("Error converting a space string to a nullable int.");

            if (stringToNullableIntConverter("57").GetValueOrDefault() != 57)
                throw new Exception("Error converting a 57 string to a nullable int.");

			var intToEnumConverter = converters.Get<int, AttributeTargets>();
			var moduleEnum = intToEnumConverter(moduleAsInt);
			if (moduleEnum != AttributeTargets.Module)
				throw new Exception("Error converting from int (underlying type) to AttributeTargets (enum).");

			var list = new List<int>();
			list.Add(57);
			list.Add(58);
			
			var listToArrayConverter = converters.Get<List<int>, int[]>();
			var array = listToArrayConverter(list);
            if (!array.SequenceEqual(list))
                throw new Exception("The array conversion did a bad job.");

			converters.Searching += AlreadyCompatibleConverter.SearchingConverterHandler;
			var intToObjectConverter = converters.Get<int, object>();
			var result = intToObjectConverter(57);

            var intStringConverter = converters.Get<int, string>();
            if (intStringConverter(57) != "57")
				throw new Exception("Error to convert int to string.");

            var untypedConvert = converters.CastedTryGet(typeof(int), typeof(string));
            var untypedResult = untypedConvert(57);
            if (!untypedResult.Equals("57"))
                throw new Exception("The untyped conversion did a bad job.");

			Stopwatch stopwatch = new Stopwatch();

			stopwatch.Reset();
			stopwatch.Start();
			for(int i=0; i<COUNT; i++)
			{
				var intValue = enumToIntConverter(AttributeTargets.Event);
				var enumValue = intToEnumConverter(intValue);
				if (enumValue != AttributeTargets.Event)
					throw new ApplicationException("Error when converting from enum to int and again to enum");
			}
			stopwatch.Stop();
			Console.WriteLine("Converting enum/int using Converters delegates: " + stopwatch.Elapsed);

			stopwatch.Reset();
			stopwatch.Start();
            var enumToIntConverterUntyped = converters.CastedGet<AttributeTargets, int>();
			var intToEnumConverterUntyped = converters.CastedGet<int, AttributeTargets>();
			for(int i=0; i<COUNT; i++)
			{
				var intValue = enumToIntConverterUntyped(AttributeTargets.Event);
				var enumValue = (AttributeTargets)intToEnumConverterUntyped(intValue);
				if (enumValue != AttributeTargets.Event)
					throw new ApplicationException("Error when converting from enum to int and again to enum");
			}
			stopwatch.Stop();
			Console.WriteLine("Converting enum/int using Converters casted delegates: " + stopwatch.Elapsed);

			stopwatch.Reset();
			stopwatch.Start();
			for(int i=0; i<COUNT; i++)
			{
				var intValue = Convert.ToInt32(AttributeTargets.Event);
				
				// I first tried this, but it does not work:
				//var enumValue = (AttributeTargets)Convert.ChangeType(intValue, typeof(AttributeTargets));
				//
				// So, the right code is this:
				var enumValue = (AttributeTargets)Enum.ToObject(typeof(AttributeTargets), intValue);
				
				if (enumValue != AttributeTargets.Event)
					throw new ApplicationException("Error when converting from enum to int and again to enum");
			}
			stopwatch.Stop();
			Console.WriteLine("Converting enum/int using Convert and Enum.ToObject: " + stopwatch.Elapsed);

			Console.WriteLine();
            Console.WriteLine("All the test conversions where done without errors.");
            Console.WriteLine("If you want to see something use the WPF application or debug the code.");
            Console.WriteLine("Press [Enter] to exit.");
            Console.ReadLine();

		}
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Microsoft
United States United States
I started to program computers when I was 11 years old, as a hobbyist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do their work easier, faster and with less errors.

Want more info or simply want to contact me?
Take a look at: http://paulozemek.azurewebsites.net/
Or e-mail me at: paulozemek@outlook.com

Codeproject MVP 2012, 2015 & 2016
Microsoft MVP 2013-2014 (in October 2014 I started working at Microsoft, so I can't be a Microsoft MVP anymore).

Comments and Discussions