Simple object conversion pattern

Here's a quick conversion pattern you can use if you've got a lot of object conversion going on within your project, especially where databases and web services are involved. Bear in mind that this is essentially what the adapter pattern handles, but doesn't involve any sort of inheritence. It's like a cruder version of that pattern. It's also not as quick to use as a simple linq projection. However, you might want to do that tranposition more than once, so you'd want to stick that logic into a utility method or something similar.

This approach just formalises that utility method and enables you to keep all these kinds of conversions in one place; under one roof, if you will.

My solution involves an interface and (optionally) a utility method. It's handy for when you've got a set of data objects that you want to easily transpose and modify in order to send through a web service call to a client. Even if Linq To Sql (for example) does support such serialisation with WCF services without having to do much work, this often isn't desirable as generally you, as the programmer, want more control over exactly which data is sent across the wire. You might want to do this to guarantee packet sizes, for example, not to mention keeping the interface intact since your domain objects will change.

Here's the interface for the converter. Objects which implement this interface support converting an object from one type to another:

public interface IConverter<TInput, TOutput>
{
	TOutput Convert(TInput input);
}

Very simple. As an example, an object which converts a series of integers to a series of strings might look like this:

public class IntConverterConverter : IConverter<int, string>
{
	public string Convert(int input)
	{
		return "Number: " + input.ToString();
	}
}

The optional utility method I mentioned earlier is simply a wrapper for converting a whole bunch of inputs in one go. It produces a list of outputs where each item in the list has been converted from each item in the input list. It's also been implemented as an extension method, so this will work with anything which implements the IEnumerable<T> interface:

public static IEnumerable ConvertAll<TConverter, TInput, TOutput>(this IEnumerable inputs)
	where TConverter : IConverter<TInput, TOutput>, new()
{

        IConverter<TInput, TOutput> converter = Activator.CreateInstance(typeof(TConverter)) as IConverter;
	List<TOutput> outputList = new List<TOutput>();

	foreach (TInput input in inputs)
	{
		outputList.Add(converter.Convert(input));
	}

	return outputList;
}

Here's an example of using this pattern to convert a bunch of domain objects to a set of data transfer objects (DTOs) with the intention of sending these objects to a WCF client. First, this is what the domain objects look like:

Person domain model

And here's the DTO I'm going to convert them to:

[DataContract]
public class PersonDto
{
	[DataMember]
	public string Name { get; set; }

	[DataMember]
	public string HomeTown { get; set; }

	[DataMember]
	public string [] EmailAddresses { get; set; }
}

The converter object to convert the domain object to the DTO is:

public class PersonDtoConverter : IConverter<Person, PersonDto>
{
	public PersonDto Convert(Person input)
	{
		return new PersonDto()
		{
			Name = input.Name,
			EmailAddresses = input.EmailAddresses.Select(e => e.Address).ToArray(),
			HomeTown = input.HomeTown.Name
		};
	}
}

 

And a quick example of converting a set of Person domain objects to a set of DTOs:

using (ExampleDataContext dc = new ExampleDataContext())
{
	var people = from p in dc.Persons

		     select p;

	var convertedPeople = ConversionHelper.ConvertAll(people);

	foreach(var person in convertedPeople)
		Console.WriteLine(person.Name);
}

So now instead of a hierarchy of objects representing a person and all the information we can associate with him, we've reduced it to a simple class with a fixed set of properties, allowing the domain object to change freely without affecting any public interfaces and services you might have. If the domain objects do change, you should only have to reflect that change in your conversion code in one place. You could go a step further and create an interface for each DTO which makes this even more flexible.

I've produced a small project containing all of the above code and the database schema for the DataContext used here, should you wish to borrow or play around with this at your own leisure.

Download the example project

Comments

There are no comments for this BlogEntry.

Leave a comment

denotes a required field