Friday, August 14, 2009

C# 3.0 - Lambda expressions in charge of DataReader operations

After a long-time usage of generics-based method to read data from SqlCommand, using IDataReader, now it seems that I'm gonna love the lambda expressions approach.

What I've used:

public delegate void RowReaderHandler<T>(IDataReader reader, T obj);

public static void RowSetReader<T>(IDataReader reader, RowReaderHandler<T> handle, T obj)
{
while (reader.Read())
{
handle(reader, obj);
}
reader.Close();
}

as a base functionalllity in an abstract class, then calling this from every implementation, as follows:

public MyClass LoadMyClassByID (int ID){
MyClass myClass = new MyClass();
SetCommandNameAndParams(SP_LOAD_BY_ID, ID);
IDataReader reader = base.GetDataReader();
RowSetReader<MyClass>(reader, FillMyClassDetails, myClass);
}

public void FillMyClassDetails (IDataReader reader, MyClass myClass){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
}


There is a better approach, using Action<T> delegates and lambda expressions. This is the method in the base, abstract class:


public void SingleRowReader(Action<IDataReader> processor)
{
IDataReader reader = Execute();
while (reader.Read())
{
processor(reader);
}
reader.Close();
}

As it's seen, here we are passing only each reader row, instead of passing the item and the reader.
The implementation therefore may seem like:
public MyClass LoadMyClassByID (int ID){
MyClass myClass = new MyClass();
SetCommandNameAndParams(SP_LOAD_BY_ID, ID);
RowSetReader(readerRow => this.FillMyClassDetails(myClass, readerRow));
}

public void FillMyClassDetails (MyClass myClass, IDataReader reader){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
}

At first sight, the differences are just syntactic, and less parameters passed in the 'lambda' example. But, digging deep, you may see that that lambdas will give us more freedom to call processing methods with variable parameters, contrary to the limitation of matching the processing method to the predefined delegate above.
Just a sample - imagine you have to pass additional parameter to the FillMyClassDetails method :

public void FillMyClassDetails (IDataReader reader, MyClass myClass, bool loadAge){
myClass.ID = reader.GetInt32(0);
myClass.Name = reader.GetString(1);
if (loadAge)
myClass.Age = reader.GetInt32(2);
}

While, in the first approach you will have to modify or add new delegate with 'params[]' parameters, in the second one you have nothing to do with the base functionallity. The only difference will be :

{
...
RowSetReader<(readerRow => this.FillMyClassDetails(myClass, readerRow, loadAge));
...
}

As lambda expression evaluates just the 'readerRow' parameter, it is irrelevant to the other part of the method parameters.
Handy, huh...

No comments:

Post a Comment