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

Connecting 2 1440p displays to a Retina Macbook Pro.

My boss very kindly bought me two Dell U2515H monitors (which are utterly, utterly lovely – best monitors I’ve ever had), which are 1440P monitors.

I had a few issues configuring them with a 2013 Macbook Pro Retina, so here’s the problems and how I solved them.

The first issue was that 1 monitor had a maximum resolution of 2048×1152. This was caused because I had 1 monitor plugged into HDMI (which worked fine) and the the other plugged in to a Thunderbolt port with a Thunderbolt → HDMI convertor. The fix was to use the included MiniDisplayPort → HDMI cable – plug the HDMI end into the monitor and the mini display port end into … the Thunderbolt port! Apparently, Thunderbolt is backwardly compatible with Mini Display Port. You learn something new every day 🙂

At this point everything was perfect in Mac OS X. However, I do most of my work in a Windows 8.1 Parallels VM, and certain applications were displaying with large, fuzzy text, as though they had been independently scaled by Windows.

Which they were…

The fix was to change the Windows DPI scaling settings. Click Start and type “Display” to find the display settings dialog. Then set the slider in “Change the size of all items” to it’s lowest setting of “Smaller”.

Display settings

And I now had 2 25″ 1440P displays, which are pretty much the perfect combination of screen-size, resolution, DPI in my view.