Showing posts with label extension methods. Show all posts
Showing posts with label extension methods. Show all posts

Tuesday, 22 January 2013

DateTime Start and End of Day Extension Methods

Another quick post with some useful extension methods for the System.DateTime struct. I've been working a lot with the DateTime type over the past couple of weeks. One particular use case has been to pass a "start" and an "end" DateTime to some SQL Server stored procedure. The stored procedure then returns some data based on some timestamp field that falls between the start and end DateTime's passed in.

In the code I was maintaining, the previous developer had created a DateTime value using DateTime.Now, which returns a DateTime with the time part also populated to the current system time. So when passing this DateTime to the stored proc as a "start" DateTime, the proc was looking from the time-part onwards on the specific day represented by the DateTime. Likewise, when using a similarly created DateTime for the "end" DateTime, the stored proc only returned rows upto the time-part. This was undesired behaviour because the original intention was to retrieve all of the records between two specified days (inclusive of the start and end days).

I decided to tackle this at the application-level. This was mainly to keep the stored procedure flexible so that it can continue to handle retrieval of records at the more granular time level if required. I decided to implement this functionality by adding two extension methods on DateTime, namely, ResetTimeToStartOfDay and ResetTimeToEndOfDay. These return new DateTime values with the time part appropriately set. The idea is to call ResetTimeToStartOfDay on the "start" DateTime and ensure that the returned DateTime is sent to the stored procedure. Likewise, call ResetTimeToEndOfDay on the "end" DateTime. I've included the implementation of the two methods below - very simple but useful to have in your library.

public static DateTime ResetTimeToStartOfDay(this DateTime dateTime)
{
   return new DateTime(
      dateTime.Year, 
      dateTime.Month, 
      dateTime.Day, 
      0, 0, 0, 0);
}

public static DateTime ResetTimeToEndOfDay(this DateTime dateTime)
{
   return new DateTime(
      dateTime.Year, 
      dateTime.Month, 
      dateTime.Day, 
      23, 59, 59, 999);
}

Tuesday, 4 December 2012

Dynamic Typing and Extension Methods

Earlier today I came across an interesting runtime exception of type RuntimeBinderException. The specific exception message was:

'System.DateTime' does not contain a definition for 'ToUKFormat'

'ToUKFormat' is a custom extension method on DateTime that I wrote and was in-scope at compile time when I called it. So what caused the runtime exception? It turns out that you cannot call an extension method on an object/value that is dynamically typed. In my case, I was using the dynamic ViewBag in an ASP.NET MVC application to store a DateTime value - then in my view, I was retrieving that value from the ViewBag and calling a custom written extension method on it ('ToUKFormat'). In razor syntax, I was doing something similar to:

@ViewBag.Foo.Bar.ToUKFormat()
I have given the solution further below but if you want to reproduce the problem in a simple console application, you can use the following code:

namespace DynamicRuntimeIssue
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic today = DateTime.Today;

            Console.WriteLine(today.ToUKFormat()); // Exception...
            Console.ReadLine();
        }
    }

    static class DateTimeExtensions
    {
        public static string ToUKFormat(this DateTime dateTime)
        {
            return dateTime.ToString("dd/MM/yyyy");
        }
    }
}
When you run the code above, you will encounter the aforementioned exception. Of course, if you appropriately type the 'today' variable to a DateTime rather than dynamic, then you'll find that it all works as expected. However, if you cannot avoid the use of dynamic, like for example in my case where I was using ViewBag - then you can overcome this exception by calling your extension method as if it was any normal static method. You call the method and pass-in your object/value through as an actual parameter. Following on from the example above, you would therefore have:

Console.WriteLine(DateTimeExtensions.ToUKFormat(today));
Rather than:

Console.WriteLine(today.ToUKFormat());
If you want to understand why you can't call extension methods on a dynamic type, then go over to this stackoverflow question where someone else has had the same issue - you will particularly want to read Eric Lippert's response dated March 15 2011.

Saturday, 4 February 2012

C# Array ForEach Method

I was recently looking at the two delegate types that the .NET BCL provides, namely, the Action(Of T) and Func(Of TResult) delegates - both can be found in the System namespace.

This post is primarily about the Action<T> delegate. You can use this delegate to store references to methods that return nothing (void) but have parameters. There are sixteen versions of this delegate, each taking an added parameter of type T (meaning you can store references to methods of up to sixteen parameters).

Both of these delegate types are provided as a convenience for the programmer. You could easily define your own delegate for your methods but it's now probably better practice to use Action<T> or Func<T, TResult> whenever you can. The example I wrote below uses Action<T> to create a nice little extension method for C# arrays (System.Array). It mimics the ForEach method on System.Collections.Generic.List<T>...

public static void ForEach<T>(this T[] sourceArray, Action<T> action)
{
    foreach (T obj in sourceArray)   
        action(obj);
}
You now have a cool way to perform an action on each item of an array without having to iterate through your array using a for loop or a foreach construct. The example use below defines a string array, then calls the ForEach, passing it a lambda expression that prints each item to console :

string[] cars = {"Porsche", "Ferrari", "Mercedes"};
cars.ForEach(c => Console.WriteLine(c));
You could also pass in an anonymous method or a named method if you don't like lambda expressions. The following example call uses an anonymous method:

cars.ForEach(delegate(string car) {
    Console.WriteLine(car);
});

Thursday, 19 January 2012

String.ParseCsvToList Extension Method

A useful extension method to System.String. Given a comma-seperated list in a string, it'll return a generic List of type string, with each value occupying its own index.

public static List<string> ParseCsvToList(this string source)
{
    var valuesArray = source.Split(new char[] {','});
    return valuesArray.Select(value => value.Trim()).ToList();
}

Sunday, 18 December 2011

String.IsNullOrEmptyWhiteSpace Extension Method

This is hopefully the first of a series of related posts on some useful Extension methods that I've written. If you're not familiar with Extension methods then think of them as additional methods that you can add to any class you want additional functionality or behaviour for. For example, you can add a new method to the .NET BCL String class (as in this post). Prior to this feature, you could achieve this by deriving from a class and adding a new method in the deriving class, but Extension methods now give you a more reusable alternative. I'd recommend reading up on this topic by clicking here.

One thing I often find myself having to do is validate a string for not being empty. One fairly primitive way to accomplish this is to test for the following condition in an if statement:

input.Equals(string.Empty)
This will return true if input is an empty string. Sometimes, however, you need to also test if the input contains empty white space. Imagine if the user accidently hit the space key and the value for input was the string "  ". The test above would return false in such a case. To cater for such scenarios, I wrote the following extension method in a class library project.

public static bool IsNullOrEmptyWhiteSpace(this string str)
{
     return (str == null || str.Trim().Equals(string.Empty));
}
The test would now look like:

if (input.IsNullOrEmptyWhiteSpace())
     //Tell user to enter something
** Update (13/03/2013) **

As of .NET 4 the static method IsNullOrWhiteSpace was added to the String datatype, therefore making the extension method above redundant (unless you're still using earlier versions of the framework :).