Bookmark and Share

Maybe as an Extension Method

A frequent question I received concerning the Maybe static class was “why didn’t you make extension methods?” I am a proponent of extension methods, so it would seem that I would prefer “42”.ToInt32() over Maybe.ToInt32(“42”). However, I immediately created a static class for this despite my previous criticisms of helper classes. Why?

Semantics

What does it mean when someone writes Request.QueryString[“index”].ToInt32()? It’s not obvious that ToInt32() returns a Nullable<int>. When I first created the Maybe class, I wanted to call it Nullable but couldn’t do so because a non-generic Nullable existed in the framework. Maybe was the next best thing: it may be an Int32, in may be null.

Responsibility

There is another problem with making these extension methods. It is far too easy to give String too much responsibility. I try to be careful when making decisions about assigning anything to a string. I fully expect someone to create a full string domain specific language with extension methods in the near future.

Extension

Okay, so I did decide to make an extension method. I felt the methods on Maybe were candidates, and it would be easy enough to add “this” to the first parameter, but I wanted to maintain semantics. What I opted for was a Maybe<T> method on string.

public static Nullable<T> Maybe<T>(this string value) where T : struct
{
    var maybe = new Dictionary<Type, Func<string, ValueType>>
    {
        { typeof(BigInteger), s => Kodefu.Maybe.ToBigInteger(s) },
        { typeof(Boolean), s => Kodefu.Maybe.ToBoolean(s) },
        { typeof(Byte), s => Kodefu.Maybe.ToByte(s) },
        { typeof(DateTime), s => Kodefu.Maybe.ToDateTime(s) },
        { typeof(Decimal), s => Kodefu.Maybe.ToDecimal(s) },
        { typeof(Double), s => Kodefu.Maybe.ToDouble(s) },
        { typeof(Enum), s => Kodefu.Maybe.ToEnum<T>(s) },
        { typeof(Guid), s => Kodefu.Maybe.ToGuid(s) },
        { typeof(Int16), s => Kodefu.Maybe.ToInt16(s) },
        { typeof(Int32), s => Kodefu.Maybe.ToInt32(s) },
        { typeof(Int64), s => Kodefu.Maybe.ToInt64(s) },
        { typeof(SByte), s => Kodefu.Maybe.ToSByte(s) },
        { typeof(Single), s => Kodefu.Maybe.ToSingle(s) },
        { typeof(TimeSpan), s => Kodefu.Maybe.ToTimeSpan(s) },
        { typeof(UInt16), s => Kodefu.Maybe.ToUInt16(s) },
        { typeof(UInt32), s => Kodefu.Maybe.ToUInt32(s) },
        { typeof(UInt64), s => Kodefu.Maybe.ToUInt64(s) },
    };

    Type type = typeof(T);
    type = type.IsEnum ? type.BaseType : type;

    if (maybe.ContainsKey(type))
    {
        return maybe[type](value) as Nullable<T>;
    }            
    
    return null;
}

** I updated the code base to move the dictionary out of the method. Creating a dictionary was unnoticeable in the operation, but I suspect someone will complain. grab the updated version of you don’t like this one.

This started out as one big set of if statements. However, it was nearly unreadable so I refactored to a dictionary. The fully qualified domain name it necessary because the method name is Maybe<T>, and there are conflicts even though the Maybe static class has no generic parameter. Which brings me to another C# lesson: you cannot add this as an extension method in the Maybe class because it has the same name as the class. I put it under String extensions.

If you’re wondering about the ValueType and the odd cast… well, without generic inference, the compiler couldn’t figure out that I was returning a Nullable<T>. I decided to cast in one place.

If you prefer the extension method way of doing things, you can call Request.QueryString[“index”].Maybe<int>() ?? 0. I still prefer helper class way of doing things, but it’s an option!

Download the source code at kodefu.codeplex.com.

blog comments powered by Disqus

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
Telerik Developer Evangelist, C# MVP

JustCode

Telerik .NET Ninja

 

INETA Community Speakers Program

 

MVP - Visual C#

 

Friend of RedGate

World Map

Tag cloud

Month List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.