I’ve been playing with the yield keyword lately. It gives you a custom iterator, and I have found it to clean up my api quite nicely.
Here is my case in point. I’m writing some code to work with the GridView. I want to go through the GridView rows, but only the DataRows (not the header or footer rows).
Normally I would write code like this:
GridViewRowCollection rows = gvTimecard.Rows; foreach (GridViewRow row in rows) { if (row.RowType == DataControlRowType.DataRow) { // do stuff here } }
That is nice, but it still doesn’t imply intent as it should. Now I’m going to create a custom iterator and rewrite the code to show intent. First I’m going to write a function using the yield keyword:
private IEnumerable<GridViewRow> GridDataRows() { GridViewRowCollection rows = gvTimecard.Rows; foreach (GridViewRow row in rows) { if (row.RowType == DataControlRowType.DataRow) { yield return row; } } }
Next I rewrite my original function:
foreach (GridViewRow row in GridDataRows()) { // do stuff here }
Note: I did note save you ANY keystrokes. In fact I created more. But that wasn’t the intent. My intent, in showing this, was in how to write code that is easier to follow and understand. I want my code to focus on WHAT it is doing, now HOW it is doing it.
For any of you who say, “If it isn’t in MSDN Magazine it doesn’t exist”, here is an article by Juval Lowy that talks about the same thing.
This is cool. How about adding you functioanlity as an extesion method to the DataGrid.Rows so that I have DataGrid.Rows.DataRows?
I thought about that (but I’m still using .Net 2.0 on my current project).
Wouldn’t DataGrid.DataRows make more sense tho?
Nice. It would be also good to have a parameterized version for this function like this:
private IEnumerable GridRows(DataControlRowType rowType)
{
GridViewRowCollection rows = gvTimecard.Rows;
foreach (GridViewRow row in rows)
{
if (row.RowType == rowType)
{
yield return row;
}
}
}
// Usage:
foreach (GridViewRow row in GridRows(DataControlRowType.DataRow))
{
// do stuff here
}