Adding setter methods to TypeMerger

I recently wanted to merge two C# objects into a single object. The objects were dumb models, so I really just wanted to copy the properties and their values.

I came across Kyle Finley’s amazing TypeMerger class, which is designed for exactly this scenario – you use it as follows:

var object1 = GetSomeObject();
var object2 = GetSomeOtherObject();
var mergedObject = TypeMerger.MergeTypes(object1, object2);

It works by creating a brand new type, on the fly, and generating a backing field and a property getter for each property in the source objects – very cool!

However, it had one limitation – it only defined a getter for each property, not a setter. I wanted to URL encode all my string properties, and this wasn’t possible.

Fortunately, the code is clearly written, so it was straightforward to update it to support setters.

Firstly, I added a new unit-test so that my OODA loop would be quicker:

        [TestMethod]
        public void VerifyThatNewTypesHaveSetters()
        {
            var result = TypeMerger.MergeTypes(new { PropertyOne = "A" }, new { PropertyTwo = "B" });

            Assert.AreEqual(true, result.GetType().GetProperty("PropertyOne").CanWrite);
            Assert.AreEqual(true, result.GetType().GetProperty("PropertyTwo").CanWrite);
            
            PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(result);

            Assert.AreEqual("A", pdc["PropertyOne"].GetValue(result));
            Assert.AreEqual("B", pdc["PropertyTwo"].GetValue(result));

            pdc["PropertyOne"].SetValue(result, "1");
            pdc["PropertyTwo"].SetValue(result, "2");

            Assert.AreEqual("1", pdc["PropertyOne"].GetValue(result));
            Assert.AreEqual("2", pdc["PropertyTwo"].GetValue(result));
        }

I then used Linqpad to write the class I wanted to be output, so that I could view the necessary IL.

Finally, I updated BuildProperties method in TypeMerger.cs to include the setter generation

private static void BuildProperties (TypeBuilder typeBuilder, FieldBuilder[] fields)
{
    // Kyle's code

    MethodBuilder setMethod = typeBuilder.DefineMethod(
        String.Format("Set_{0}", propertyName),
        MethodAttributes.Public | MethodAttributes.SpecialName,
        null,
        new Type[] { fields[i].FieldType }
    );

    ILGenerator setMethodGenerator = setMethod.GetILGenerator();
    setMethodGenerator.Emit(OpCodes.Ldarg_0);     // load this
    setMethodGenerator.Emit(OpCodes.Ldarg_1);     // load value
    setMethodGenerator.Emit(OpCodes.Stfld, fields[i]); // store into field
    setMethodGenerator.Emit(OpCodes.Ret); // return

    property.SetSetMethod(setMethod);
}

Et voila!

Advertisements

One thought on “Adding setter methods to TypeMerger

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s