Showing posts with label Extension Methods. Show all posts
Showing posts with label Extension Methods. Show all posts

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.

Tuesday, April 22, 2008

C# Extension Methods Part 2: Extending Log4Net

OK, so after last time's brief introduction I'll share with you a Log4Net extension that I've made. It's nothing really too complicated but I hope it will highlight what I feel are the advantages of this technique.

So, on to business. If you're like me you'll like your logging code. I think logs are wonderful, if only to check that your code is doing what you think it is. Of course, there's always the chance that you'll have too much logging, but that's what log levels are for, right? ;)

The following is a common pattern I use for logging at pretty much every level (I've shown Debug here):

int someValue = 3;
if (log.IsDebugEnabled)
{
log.DebugFormat("This is a value: {0}", someValue);
}

Here I have a value I want to log, so I check that we should log and then log out the value. In this case I guess the check is superfluous, as the statement won't be output if we're not logging at debug anyway, but I like to get into the habit of checking so that when I need to log something like this:

if (log.IsDebugEnabled)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100; i++)
{
builder.Append(GetSomeLogStatement(i));
}

log.Debug(builder.ToString());
}

I only go into the long running loop if I'm going to get some logging output from it.

When debugging code I like to have log statements that show where the execution path is going. The easiest way of doing that is to output a log statement when you enter a public method, but if you're doing this a lot then that's a lot of code being reproduced.

That's when I thought about making an extension method to handle all this for me. Here's the code:

public static void LogMethodParameters(this ILog logger, Level level,
string methodName, params object[] parameters)
{
try
{
if (logger == null)
{
throw new ArgumentNullException("logger");
}

if (level == null)
{
throw new ArgumentNullException("level");
}

if (methodName == null)
{
throw new ArgumentNullException("methodName");
}

if (logger.Logger.IsEnabledFor(level))
{
StringBuilder builder = new StringBuilder();
builder.AppendFormat("Method: [{0}]. ", methodName);
if (parameters != null && parameters.Length > 0)
{
// parameters.Length is at least 1
builder.AppendFormat("Parameters: (p0: [{0}]", GetParameterDisplayValue(parameters[0]));
for (int i = 1; i < parameters.Length; i++)
{
builder.AppendFormat(", p{0}: [{1}]", i, GetParameterDisplayValue(parameters[i]));
}
builder.Append(")");
}

logger.Logger.Log(null, level, builder.ToString(), null);
}
}
catch (Exception ex)
{
log4net.Util.LogLog.Error("Exception while logging exception", ex);
}
}

private static object GetParameterDisplayValue(object param)
{
return param != null ? param : "(null)";
}

public static void DebugMethodParameters(this ILog logger,
string methodName, params object[] parameters)
{
LogMethodParameters(logger, Level.Debug, methodName, parameters);
}

Like I say, it's nothing too complicated, but it allows you to include this line at the top of each of your public methods:

log.DebugMethodParameters("Method", 1, 2, 3);

And you don't need to worry about anything else, your log file will show that you entered the method with those parameters.

What I wanted to do was use reflection to figure out what the current method was and what the parameter values are, but this was just a little side task I had to do while in the middle of something else.

Here are some additions I could make to this method:
  • Use reflection to get the method name and parameter names
  • Incorporate the Visual Studio 2008 ObjectDumper sample to drill down into complex objects to provide a fuller picture of non-primitive types
  • Allow custom formatting of the log output
This is just the start really. Check out extensionmethod.net for some more samples of what else you can do. (Hmm, that site seems to be having a few problems at the moment, but check back later and browse what they have).

Saturday, April 19, 2008

C# Extension Methods Part 1: Introduction

Extension methods are a new feature of C# 3.0 with .Net 3.5. They allow you to extend existing classes with new methods without having to create a whole new class that inherits from the class you want to add the method to. First off, why would you want to do this?

Well, as an example LINQ makes heavy use of extension methods to provide the functionality to create new expressions easily. A LINQ extension method might extend IQueryable to apply a custom where clause, for example. In fact, as part of the Visual Studio 2008 samples you'll find a set of extension methods that does just that.

So what does an extension method look like? Here's a very simple example:

public static string Reverse(this string str)
{
if (str == null)
{
throw new ArgumentNullException("str");
}

StringBuilder builder = new StringBuilder();
for (int i = str.Length - 1; i >= 0; i--)
{
builder.Append(str[i]);
}

return builder.ToString();

}

Here we have a static class StringExtensionMethods that contains a Reverse method, which reverses the order of the characters in a string.

Notice that the parameter being passed into the Reverse method has the "this" keyword preceding it. This tells the compiler that this is an extension method for the string class.


You can now use this method on any string object in any class that uses the namespace that this static class is in. We also get full Intellisense support in Visual Studio 2008:

reverseCodeGrab


There are a few things to be aware of though. Consider this piece of code:

string thisIsNull = null;
Console.Write(thisIsNull.Reverse());

If Reverse was a standard method on the string object, then we would get a NullReferenceException being thrown when we try to call the method.

However, an extension method on a null object will still be called. It is the responsibility of the extension method to check for null values.

The extension method is pretty much just syntactic sugar around a standard static "helper" style method. So when the method is called it doesn't actually need to be part of an instance.

For this reason, make sure you should still check that the parameter is not null before using it, as you would in a normal method.
As a quick aside, this is a perfectly functional extension method:

public static bool IsNull(this object obj)
{
return obj == null;
}

It could then be called like this:

string thisIsNull = null;
if (thisIsNull.IsNull())
{
Console.Write("Was null");
}

So we can create extension methods that easily provide some additional functionality to a class. Next time, I'll show how I've implemented a simple extension method to Log4Net.