Monday, May 26, 2008

Refactoring

I've currently got a post on ice about using CLR functions in SQL Server 2005 using LINQ (don't worry Paul, I've not forgotten), but while I mull that over I'll just make a short point about refactoring code.

Regular readers (and Google Analytics tells me that I do have some, at least), might have picked up on a few complaints I've had about VB.Net. Personally I wish I'd never have to use it, but sometimes rewriting an entire app in C# isn't cost effective so... needs must, and all that.

Well, I was recently in the midst of a ton of VB.Net code, thinking "I could do with some IDE refactoring support here," after needing to extract a code block into its own method. Except I can't find any such support in Visual Studio 2008 for such an option.

Using C# in Visual Studio (2005 and 2008), we have a neat little context menu option called Refactoring, and while it doesn't offer the depth of features that something like Resharper offers, it at least allows you to Extract Method, which was the refactoring technique I needed to use.

Long story short, I found this post from the VB.Net Technical Lead:
I’d never even heard of refactoring until C# added the feature to their IDE. I’ve never bought a copy of, much less read, Refactoring: Improving the Design of Existing Code.

I let out an audible sigh after reading that. In a way it explains a great deal about VB.Net.

Refactoring should be something that every professional developer knows about and practices every day of their working lives. It is an integral part of the development cycle, and one which even graduates should at least be aware of.

If we do not refactor we end up repeating code needlessly. Although this might produce a working application that passes all current tests, put yourself 6 months, or 6 years down the line where you have to add a new database table, or a column to a table, or a new page to your web application.

If you've essentially been copy and pasting code, how many places in the code base do you have to change to add that small piece of new functionality? Answer: unknown, especially if you weren't involved in the initial project. How do you know that you've caught all the places without executing every branch of the application?

Answer: you don't, not until you get irate customers yelling at you, and your managers asking why such a small change resulted in the entire app breaking.

And it's such a simple thing that I have difficultly believing that any developer worth their salt wouldn't see the benefits that it gives. So if you don't know, then read up and get using it. Your code can only get better.

Wednesday, May 07, 2008

IEnumerable to DataSet Extension Method

I recently had a need to create a DataSet from a List<T>, and found this post that did just that. I was happily using that in C# code, but then had a requirement to use it from a VB.Net app.

I'm not even going to attempt to hide my contempt for VB, and one of the things that I quickly tire of is typing the exact same thing multiple times. The Intellisense in VB also doesn't seem as smart as it is in C#, mainly it doesn't help as much when instantiating objects.

So I wanted a simpler way of calling the code that I had from the post above, and I immediately thought of extension methods. If I could create an extension method that made a DataSet from an IEnumerable then I could call that from the VB app with a minimal of fuss.

Kudos must go to Keith Elder for his original code, but if you want it in extension method form, then here it is:

public static class CollectionExtensions
{
public static DataSet ToDataSet<T>(this
IEnumerable<T> collection, string dataTableName)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}

if (string.IsNullOrEmpty(dataTableName))
{
throw new ArgumentNullException("dataTableName");
}

DataSet data = new DataSet("NewDataSet");
data.Tables.Add(FillDataTable(dataTableName, collection));
return data;
}

private static DataTable FillDataTable<T>(string tableName,
IEnumerable<T> collection)
{
PropertyInfo[] properties = typeof(T).GetProperties();

DataTable dt = CreateDataTable<T>(tableName,
collection, properties);

IEnumerator<T> enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
dt.Rows.Add(FillDataRow<T>(dt.NewRow(),
enumerator.Current, properties));
}

return dt;
}

private static DataRow FillDataRow<T>(DataRow dataRow,
T item, PropertyInfo[] properties)
{
foreach (PropertyInfo property in properties)
{
dataRow[property.Name.ToString()] = property.GetValue(item, null);
}

return dataRow;
}

private static DataTable CreateDataTable<T>(string tableName,
IEnumerable<T> collection, PropertyInfo[] properties)
{
DataTable dt = new DataTable(tableName);

foreach (PropertyInfo property in properties)
{
dt.Columns.Add(property.Name.ToString());
}

return dt;
}
}

It creates a DataSet with one table that has the name you pass in. In my case I didn't need to name the DataSet explicitly so just used a constant, but the code above could easily be updated to pass in a DataSet name if you need it.

Now you should be able to call ToDataSet on any object that implements the IEnumerable interface.