I'm working with a SOA architecture that's forcing me to bend, fold, spindle, and mutilate objects as they move across tiers. This is awkward, but it's a common side-effect of splitting applications across tiers. One of the implications of this design is that objects have to be translated, or copied value by value across tiers.
This work is pretty straightforward, but it's tedious, and worse, it doesn't add any value to the software -- it's just plumbing. Boy, I thought, wouldn't it be nice to be able to hook two equivalent objects up and move values from one to the other automatically.
Enter reflection. Now, before I show the goodies, you'll want to be careful where you use this. Reflection isn't as efficient as writing early-bound code, but when used sparingly, it can haul a lot of groceries with very little code. If nothing else, use this as a quick primer on reflection. It's not as hard as many people think, and it's a great technique to have in your toolbox.
Here's the code. If I were to enhance it, I might have it raise an event when it comes across a property it can't match, so a consumer could handle custom maps in-line. I think it would also be great to use this as the basis for a Visual Studio addin to manufacture early-bound code for translation - sort of like the translator wizard in the Web Services Factory, but a little more automatic. Have fun with it...
public class Translator
{
/// <summary>
/// Use reflection to copy as many properties from the "from" object
/// to the "to" object as possible, matching properties by name.
/// </summary>
/// <param name="objFrom">Copy from object</param>
/// <param name="objTo">Copy to object</param>
public static void Translate(object objFrom, object objTo)
{
Type tFrom = objFrom.GetType();
Type tTo = objTo.GetType();
//Get the properties of our type
PropertyInfo[] fromProps = tFrom.GetProperties();
foreach (PropertyInfo pInfo in fromProps)
{
try
{
object[] fromValue = new object[1];
fromValue[0] = tFrom.InvokeMember(pInfo.Name, BindingFlags.GetProperty, null, objFrom, null);
tTo.InvokeMember(pInfo.Name, BindingFlags.SetProperty, null, objTo, fromValue);
}
catch (Exception ex) { }
}
}
}