Tuesday, December 29, 2009

Casting / Converting in .NET via ASP.NET Weblogs

Level

Beginner



Introduction

The basic thing at least you code is converting one type to other. There are so many methods and a dedicated class (Convert class) provided in .Net framework for the same. And Microsoft has provided better approaches and practices for efficient conversion like TryParse. Here, I am sharing my experience for casting and converting one type to other. In this post we see the basic data types like string, int and DateTime.



What are the problems?


Developers follow different approaches for getting the desired result. In my team I have seen the most usage of ToString. Whenever there is a need of string, we used to put .ToString() and for other data types, Convert.Whatever. Is it correct? Well, .Net will not have control on the input object what you have provided. I mean, it will throw compile errors if the expected type is not provided, but during runtime only it can say whether the provided input can be converted or not. Let’s assume a simple scenario. Let’s assume that this blog posts have post id and based on post id the data is retrieved. On click of any post, the page requests for corresponding post by passing this post id as query string or directly from URL(if is MVC). Since, I know the post id is integer, am using Convert.ToInt32 method to convert a string to int. This will work perfectly in normal conditions. But as said "Never trust external data", what happens, if the user changes id manually?? What happens if url weblogs.asp.net/fayaz/posts/csharp/123(typical MVC style) is modified to weblogs.asp.net/fayaz/posts/csharp/123abc?? Exception... And I feel application should not throw Exceptions for these small things. We can handle it in better way and can pass a message to user that invalid id is provided or some better way of handling.



Let’s Start

Let’s see the better approach for string, int and date time.



to String

The most common operation performed by any developer is converting a type to String. This can be offered to any type since all types are inherited from object and any object can be converted to string. Generally there are two ways to convert to string. One is ToString from Convert class and the other is ToString method in each type. If you search for what is the difference between Convert.ToString() and .ToString(), you will get tons of sites explaining the difference. And that will be the way of handling nulls. A Convert.ToString will return empty if the passed object is null, whereas .ToString() throws a NullReference exception, the most loved "Object reference not set to an instance of an object".



string nullString = null;

string resultString = string.Empty;

resultString = Convert.ToString(nullString); // returns empty

resultString = nullString.ToString(); // throws NullReferenceException



Obviously, we should use Convert.ToString where there are chances of null, like casting a session or viewstate to string. There are lots of scenarios like everywhere we can expect null. So, use Convert.ToString. Do you like ToString more than Convert.ToString?? Well, I love ToString and am used to it. Typing Convert.ToString and using every where is pretty difficult for me. Then I followed ExtensionMethods(framework should be 3.0 or Higher). I wrote an extension method for the same.



public static class ExtensionMethods

{

public static string ToStringOrEmpty(this object value)

{

return value == null ? string.Empty : value.ToString();

}

}



If you use exntension methods, then the code snippet would be...



string nullString = null;
string resultString = nullString.ToStringOrEmpty();



to Int

We can convert to int by using Convert.ToInt32 and int.Parse. The difference would be the same as we discussed in ToString. If null is passed to Convert.ToInt32, it returns default of int i.e., 0(zero). Whereas int.Parse throws ArguementNull exception. The difference is clear. Convert.ToInt32 has 19 over loaded methods including object, where as int.Parse has only 4 overloaded methods (no object). So, Convert.ToInt32 can handle null also.



string nullString = null;

int resultInt;



resultInt = Convert.ToInt32(nullString); // returns 0

resultInt = int.Parse(nullString); // throws ArguementNullException



Ok. We handled null a better way. Is it enough?? What if the value is some text which cannot be converted to int?? Is Convert.ToInt32 is handling this?? No, if you are passing an invalid text to convert it into int, then we get Format exception, "Input string was not in a correct format."



string invalidInt = "abc";

int resultInt;

resultInt = Convert.ToInt32(invalidInt); // throws FormatException

resultInt = int.Parse(invalidInt); // throws FormatException



Here it comes, the wonderful feature "TryParse". TryParse is similar to int.Parse, except it does not throw exception if the conversion fails.



string invalidInt = "abc";

int resultInt;

bool isInteger = int.TryParse(invalidInt, out resultInt); // resultInt = 0, isInteger = false



Check, if the return bool is true. If false, say that, the input is invalid.



If you use .net 3.0 or higher, then define your own extension method, ToInt



public static class ExtensionMethods

{

public static bool IsInt(this string value)

{

int num;

return int.TryParse(value, out num);

}



public static int ToInt(this string value)

{

int num;

int.TryParse(value, out num);

return num;

}

}



Here, we have two extension methods offered for a string. One is to check whether the input can be converted to int. And the other is returning int, if valid, else returning 0(zero).



to DateTime

This is similar to int discussion. So, am not going to elaborate. For null, Convert.ToDateTime returns default of DateTime, i.e., 1/1/0001 12:00:00 AM and DateTime.Parse throws exception.



string nullString = null;

DateTime resultDateTime;



resultDateTime = Convert.ToDateTime(nullString); // returns 1/1/0001 12:00:00 AM

resultDateTime = DateTime.Parse(nullString); // throws ArguementNullException

And for invalid data to be converted to DateTime...





string invalidDateTime = "12-12-12 12:12:12 AP";

DateTime resultDateTime;

bool isDateTime = DateTime.TryParse(invalidDateTime, out resultDateTime); // resultDateTime = 1/1/0001 12:00:00 AM, isDateTime = false



And Extension Methods will be



public static class ExtensionMethods

{

public static bool IsDateTime(this string value)

{

DateTime dt;

return DateTime.TryParse(value, out dt);

}



public static DateTime ToDateTime(this string value)

{

DateTime dt;

DateTime.TryParse(value, out dt);

return dt;

}

}



Conclusion


The views I have shared are better IMHO. They may not necessarily confirm to best practice. I am glad; if someone suggests me some better approaches. Will try to post converting objects from one form to other form shortly.