March 27, 2009

On reflecting extension methods in C#

Extension methods are a great way of adding functionality to existing classes. It almost makes C# similar to ruby/javascript, where none of the classes are "closed" - functionality can be added to them at any point of time.

For example, say we want the method ToTitleCase to be available to all String objects, and we define an extension method.
namespace MyExtensions
{
    public static class StringExtensions
    {
        public static String ToTitleCase(this String word)
        {
            return word[0].ToString().ToUpper() + word.Substring(1).ToLower();
        }
    }
}
Now, wherever we want to use the method ToTitleCase, we include the namespace MyExtensions, and the following becomes valid C# code :
        [TestMethod]
        public void TestCall()
        {
            Assert.AreEqual("Company", "COMPANY".ToTitleCase());
            Assert.AreEqual("Company", "company".ToTitleCase());
            Assert.AreEqual("Company", "Company".ToTitleCase());
        }
However, C# extension methods are simply syntactic sugar. Any extension method calls in source, such as the ones above, are transformed by the compiler into this :
        [TestMethod]
        public void TestCallClassic()
        {
            Assert.AreEqual("Company", StringExtensions.ToTitleCase("COMPANY"));
            Assert.AreEqual("Company", StringExtensions.ToTitleCase("company"));
            Assert.AreEqual("Company", StringExtensions.ToTitleCase("Company"));
        } 
The extension methods for any given type available to the compiler, but they are compiled as regular static function calls. Feels like cheating, I tell you.

Now what happens when we try to invoke an extension method via reflection?
        [TestMethod]
        public void TestMethodInfoInTargetClass()
        {
            // We won't find the method in String ...
            Assert.IsNull(typeof(String).GetMethod("ToTitleCase"));
        }

        [TestMethod]
        public void TestMethodInfoInDefinigClass()
        {
            // But we will find it in StringExtensions.
            Assert.IsNotNull(typeof(StringExtensions).GetMethod("ToTitleCase"));
        } 
This should be obvious - we aren't going to find them on the target type - we'll find them in the class where they are defined.

So, how does this affect us?

Say you're browsing through some source code, and you see a call like this - myObject.someMethod(). If you need to call the method someMethod() dynamically, you can't use the type of myObject to reflect it. Instead, you need to know if someMethod() is an extension method, and if it is, you need to reflect it off the class in which it is defined.

That solves the problem when we know which extension method we need to call. If we don't, and we want to know all the extension methods available for a given type, we can use the attribute ExtensionAttribute. This attribute indicates that a method is an extension method, or that a class or assembly contains extension methods. Given this, we can implement a function that returns all extension methods defined for a given type.
        IEnumerable <MethodInfo> GetAllExtensionMethods(Type targetType)
        {
            return
                from assembly in AppDomain.CurrentDomain.GetAssemblies()
                where assembly.IsDefined(typeof(ExtensionAttribute), false)
                    from type in assembly.GetTypes()
                    where type.IsDefined(typeof(ExtensionAttribute), false)
                    where type.IsSealed && !type.IsGenericType && !type.IsNested
                        from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
                        // this filters extension methods
                        where method.IsDefined(typeof(ExtensionAttribute), false)
                        where
                            // is it defined on me?
                            targetType == method.GetParameters()[0].ParameterType ||

                            // or on any of my interfaces?
                            targetType.GetInterfaces().Contains(method.GetParameters()[0].ParameterType)

                            // or on any of my base types?
                            targetType.IsSubclassOf(method.GetParameters()[0].ParameterType)
                        select method;
        }
The above method was inspired by Jon Skeet's answer on Stack Overflow. It simply improves on it by detecting for interfaces and base types, and looking in all assemblies in the current AppDomain.

Update: Fixed some code up there.

March 23, 2009

I flew, and how!

We were a bit late in our plans, but finally Samson gave the go-ahead.
We'll be taking off from the other end of the beach. See you there in five minutes.
The "other" end of the beach was quite some distance away. The wind sock put up to guage the wind velocity was too far to be visible. Barbara and Pascal decided to walk it up, and I took up the risk of pillioning with Joel. We found the wind sock in a couple of minutes - it was barely flying. Not very inspiring, and Joel found it amusing.
Don't worry. If there's not enough wind for these guys to make you fly, I'll pull the three of you with my bike.
Fat chance.

Samson and Mangesh arrived on a bike soon after, with the winch in tow. Now, Joel is among the healthier people around, and Mangesh did not seem too pleased to see him, but tried to put it across very diplomatically ...
We'll need a lighter person for the first ride ... let's not challenge the conditions right away. Around 50 kgs ... ?
Barbara was still a fair distance away, though. I said I was around 73. So long as it was not Joel, it was apparently ok.

I started putting on the gear. Knee-caps and a helmet. I wonder if they could help me survive a 1000 ft fall. Seemed like a moot point. But I was wrong, they would help me soon.

Barbara and Pascal reached soon after. They were both apparently happy to know they weren't the first ones on the ride. And along with Joel, they tried to unsettle me a bit.
Arre pehla bakra mil gaya inko ... tujhse hi poore equipment ki testing hogi.
Mangesh did a quick round of the basics with me. Apparently the gliders are very safe, they are designed to quickly recover from most accidents during flight. Each glider has a glide ratio -
For a glide ratio of 7:1, if you drew a horizontal of 7ft, and drew a vertical of 1ft downwards, you would be flying along the hypotenuse.
He also talked about thermals, wind currents that move upwards due to uneven heating of land. They'd help us gain altitude, but they also bring turbulence. We were on the beach, we weren't expecting a lot of them.

We were almost ready now. Last minute instructions were doled out. Hands down the sides, within all the hanesses. Run straight, and dont stop. I told Mangesh that it would be a bit awkward to run with both hands tied down, but he said it would only last for 5-6 seconds. As the glider went overhead, the harnesses would loosen. Seemed doable. The wind was ok, not too much of it. Too little, maybe. The winch was attached.
73 kg, NIL wind. Over.
Once the conditions were confirmed, we were all set to go. The two men by my side grabbed my arms, and pulled me. I ran, or at least tried to ...

The glider gained a bit of height, and my feet were airborne. The gilder came down again, however, and my feet didn't find the ground. I lost my balance, and ...


(somehow, I have a feeling that this will be the most watched video in this post ...)

As we fell, Mangesh let the release latch go. The winch separated, and took off with a jerk. Joel didn't understand what happened, and was a bit concerned.
Arre rassi kaise nikal gaya?
I got up, and dusted myself. Barbara had commented earlier in the day that I still liked to play in the mud. I got a whole lot of it on myself now. One of the knee caps was left behind, a fair distance behind. You never need these safety precautions, until you do.

We had to try again. The glider was set up behind us, the winch re-attached. We got set again. I was told that it was all up to me - the pilot couldn't do squat if I wouldn't pick up speed. As the winch started pulling, so did these guys, and they shouted -
Run, run, RUN!!!
And run I did.


The whole experience was surreal - I hadn't felt anything like it before. As the winch pulled on us, and we went higher and higher, I couldn't help feeling that I was reaching the point of no return - that a fall from this height would be fatal. But those thoughts subsided in a few seconds - the glider was extremely comfortable. Mangesh was pretty cool, though - he must've done this million times. He knew the answer, yet he asked -
Wonderful, isn't it?
And yes it was. Pascal took along his camera with him when he went up (the third flight of the day, after me and Barbara), and shot this amazing video.



It was wonderful up there. Mangesh kept talking, about the glider, about the winds, and the scene below, but frankly I dont remember much of it. I was busy enjoying the view.

We really have Samson, and the Space Apple club, to thank for this wonderful experience. If you want to know more about such events in the Vasai-Virar region, you can visit their website.

There are also a few photos of the day on my picasa album.