Friday, November 19, 2010

Must Have String Extensions

There is a great deal of love and hate toward extension methods. I will not digress into this debate, but I will give my opinion on when and where I feel extension methods are applicable and useful. For me, the rules are simple:

  1. Does it reduce the amount of code I would have to write if the extension method did not exist?
  2. Is there no other way to reduce my code by using existing framework code?
  3. Can I use this extension in multiple places throughout my project or even carry it with me across several projects?
With that in mind, I would like to share a few of my "must have" string extensions that follow me from project to project.

 
public static class StringExtensions {
    public static int ToInt32(this string s, int defaultValue) {
        try {
            return Convert.ToInt32(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static int? ToInt32N(this string s, int? defaultValue) {
        try {
            return s == null ? null : (int?)Convert.ToInt32(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static decimal ToDecimal(this string s, decimal defaultValue) {
        try {
            return Convert.ToDecimal(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static decimal? ToDecimalN(this string s, decimal? defaultValue) {
        try {
            return s == null ? null : (decimal?)Convert.ToDecimal(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static Guid ToGuid(this string s, Guid defaultValue) {
        try {
            return new Guid(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static Guid? ToGuidN(this string s, Guid? defaultValue) {
        try {
            return s == null ? null : (Guid?)new Guid(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static DateTime ToDateTime(this string s, DateTime defaultValue) {
        try {
            return Convert.ToDateTime(s);
        }
        catch {
            return defaultValue;
        }
    }

    public static DateTime? ToDateTimeN(this string s, DateTime? defaultValue) {
        try {
            return s == null ? null : (DateTime?)Convert.ToDateTime(s);
        }
        catch {
            return defaultValue;
        }
    }
}

The possibilities of application are endless.  However, I will give a few comparisons of how these methods might reduce your code.

Parsing QueryString values in a web application
BEFORE
 
    int id;
    if (!int.TryParse(Request.QueryString["id"], out id)) {
         id = 0;
    }
    
    int idn? = null;
    if (int.TryParse(Request.QueryString["id"], out id) {
        idn = id;
    }

AFTER
 
    int id = Request.QueryString["id"].ToInt32(0);
    int? idn = Request.QueryString["id"].ToInt32N(null);

Parse text from an input control
BEFORE
 
    DateTime dob;
    try {
        dob = Convert.ToDateTime(txtDob.Text);
    }
    catch {
        dob = DateTime.MinDate;
    }
    Employee emp = new Employee {
        FirstName = txtFirst.Text,
        LastName = txtLast.Text,
        DateOfBirth = dob
    }

AFTER
 
    Employee emp = new Employee {
        FirstName = txtFirst.Text,
        LastName = txtLast.Text,
        DateOfBirth = txtDob.Text.ToDateTime(DateTime.MinDate)
    }

You might wonder about the nullable methods (i.e. ToInt32N, ToDecimalN, etc...). The differences are subtle, but they are there. For example, the following use of ToInt32N is dangerous:
 
    int i = somestring.ToInt32N(25).Value;
Most of the time this will work as expected. However, if the value somestring happens to be null you will get an exception because ToInt32N will evaluate to null.

I often wonder why these type string methods have not found their way into the .Net Framework. To me they just seem so intuitively useful. Perhaps they will make it into the framework someday. Until then, the above extensions will be pervasive in my code.

No comments:

Post a Comment