Monthly Archives: November 2010

A cool List .Sort() extension method via lambda

Here’s an awesome List<T>.Sort() extension method:

    public static List<T> Sort<T,U> ( this List<T> Source, Func<T,U> OrderFunc ) {
return Source.OrderBy( OrderFunc ).ToList();
}

Use it with a lambda like this:

    MyList<SomeClass> mylist = PopulateList();
    mylist = mylist.Sort( i => i.Sequence ); 
ow that’s an awesome sort function!

Or like this for non-:

    MyList<int> mylist = PopulateList();
    mylist = mylist.Sort( i => i );

Now that’s a cool sort function!

Rob

Google Maps JavaScript API v3 Demo

I was honored to speak at the Google Technology User Group last night.  To combine a love of JavaScript, a very powerful tool, and an audience of enthusiastic fans is an incredible joy.

The topic was Google Maps, and specifically the Google Maps JavaScript API version 3.  v3 simplifies and streamlines the api in some very significant ways over v 2.  Most notably, you no longer need an API key, you only need to include a script tag.  That is awesome!

We started from a wonderfully simple “hello world” map, built up through creating Markers and pop-ups (called InfoWindows), worked through geolocation (address to Lat/Lng) and reverse geolocation (Lat/Lng to address), using the user’s location (browser permitting), and handling map events.  The crescendo of our activity was events.html:  When the user clicked the map, we created a marker and sidebar content.  Clicking either the marker or the sidebar content opened the InfoWindow and changed the sidebar’s style.  Both the pop-up InfoWindow and the sidebar content included a geolocated address.  Dragging the marker would adjust the address in the pop-up and sidebar.  An [X] button in the sidebar could show and hide the points.  It was truly awesome!  All the code we explored is available here.  There were no slides as everything was a live demo from the code.  The bottom few items on the index page include links to helpful resources, including the official Google Maps Javascript API docs found here.

Rob

Get all Enum values as a List

Often times it’s helpful to get a list of all defined values for an enum.  Enum.GetValues( typeof( MyEnumType ) ) returns an Array.  This is less than helpful.  An untyped Array is harder to query against than something much more IQueriable<T>.

So I typically write something like this:

Type t = typeof(MyEnumType);
Array vals = Enum.GetValues( t );
List<MyEnumType> enumvals = new List<MyEnumType>();
foreach ( T val in vals ) {
    enumvals.Add( val );
}

After writing this code a dozen times, it occurred to me that an extension method was in order.  Here’s the extension method:

public static List<T> GetListOfEnum<T>() {

    Type t = typeof(T);

    if ( !t.IsEnum ) {

        throw new ArgumentOutOfRangeException( t.FullName + ” is not an Enum” );

    }



    Array vals = Enum.GetValues( t );

    List<T> enumvals = new List<T>();

    foreach ( T val in vals ) {

        enumvals.Add( val );

    }



    return enumvals;

}

Call it like this:

List<MyEnum> vals = ExtensionMethodClass.GetListOfEnum<MyEnum>();

(yeah, since I didn’t have a this parameter, and didn’t really want to create a value to call an extension method, it’s really just a static method in some utility class.  That’s fine though.)

Ideally I’d like to say where T : Enum (so I’d get a compile error if I passed in a non-Enum T) but where specifically blocks Array, Delegate, Enum, ValueType, and object.  Rats.  Many have argued this should be allowed, but it isn’t.  Thus the check / throw at the top.  Some have suggested to use where T : struct or where T : IConvertable first to get 1/2 way there before the run-time check.  In the end, I suppose the answer is always the same: have good unit tests.

The last time I built this (non)extension method, ReSharper asked if it could help.  I said yes, and it turned it into this:

public static List<T> GetListOfEnum<T>() {

    Type t = typeof(T);

    if ( !t.IsEnum ) {

        throw new ArgumentOutOfRangeException( t.FullName + ” is not an Enum” );

    }

    return Enum.GetValues( typeof(T) ).Cast<T>().ToList();

}

Now that’s pretty compact!  Nice.

Rob

GetCookies Safely

The broken code:

HttpCookie cookie = Request.Cookies[“cookiename”];
if ( cookie != null && !string.IsNullOrEmpty( cookie.Value ) ) {

The problem: this code will create an entry named “cookiename” in the Request’s Cookies dictionary.  If you’re early enough in the event cycle that it hasn’t copied cookies from Request.Cookies to Response.Cookies, it’ll send your dummy entry with the response to the browser as a new cookie — even if you do nothing else with it!  This is bad.

Why have code like this?  Probably because this:

Response.Cookies[“cookiename”] = new Cookie( “cookiename”, “somevalue” );

is easier than this:

if ( Response.Cookies[“cookiename”] != null ) {
    Response.Cookies[“cookiename”] = new Cookie( “cookiename”, “somevalue” );
} else {
    Response.Cookies.Add( new Cookie( “cookiename”, “somevalue” ) );

}

(But I don’t think the former one works either.)

OK, we’ve identified the problem, how do we fix it?

I’ve created this extension method to get cookies “safely” — e.g. to avoid creating them by accident:

public static HttpCookie GetCookieSafely( this HttpCookieCollection Cookies, string CookieName ) {

    HttpCookie cookie = null;

    if ( new List<string>( Cookies.AllKeys ).Contains( CookieName ) ) {

        cookie = Cookies[CookieName]; // This will create it if it doesn’t exist already

    }

    return cookie;

}

Call it like this:

HttpCookie cookie = Request.Cookies.GetCookieSafely( “cookiename” );
if ( cookie != null && !string.IsNullOrEmpty( cookie.Value ) ) {

I’ve written this function a few times, and changed my mind often on what it should look like.  Sometimes I pass in an HttpRequest so usage is Request.GetCookieSafely( “cookiename” ).  Sometimes I extract cookie.Value and just return a string.  Sometimes I look for the cookie like this: if ( Cookies.AllKeys.ToList().Contains( CookieName ) )


What is the “perfect” extension method?  Not sure.  But now I’m not creating cookies in the Request by accident anymore.

Rob