tags:

views:

436

answers:

2

Hello Functional C# Friends,

So this time i am trying to compact my code and write in more functional , lambda style, as well as i would like to avaoid creating unneccessary lists and classes and let compiler do the work for me. I did manage to convert some small piece of code in functional way but after that i dont have much idea as how to go about.

var errorList = new List<DataRow>();

IEnumerable<DataRow> resultRows = GetResultRows();

resultRows      
     .Filter(row => row.Field<string>("status").Equals("FAILURE", StringComparison.InvariantCultureIgnoreCase))
     .ForEach(row => { errorList.Add(row); });

if (errorList.Count > 0)
{
    var excludedBooks = new List<string>();
    foreach (DataRow row in errorList)
    {
        if (ToUseBooksList.Contains((string)row["main_book"]))
        {
            BookCheckResults.AddRow(string.Format("Error for MainBook {0}, RiskType {1}",
                                                  row["main_book"], row["risk_type"]));
            if (!excludedBooks.Contains((string)row["main_book"]))
            {
                excludedBooks.Add((string)row["main_book"]);
            }
        }
    }
}

My Extension methods :

public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
    if (collection == null)
        throw new ArgumentNullException("collection");
    if (action == null)
        throw new ArgumentNullException("action");

    foreach (var item in collection)
        action(item);
}

public static IEnumerable<T> Filter<T>(this IEnumerable<T> source, Predicate<T> func)
{
    foreach (var item in source)
    {
        if (func(item))
            yield return item;
    }
}

I will highly appreciate if you can help me structing this code is more functional, lambda style.

+9  A: 

Why on earth did you write you own Filter extension method when Where is available?

leppie
you dont have Where linq extension available on IEnumerable<DataRow> hence my own filter. Can you explain how do you get Where extension of IEnumerable<DataRow> ?
netmatrix01
AG, I am confused by your question. Your implementation of Filter is EXACTLY what the implementation of Where does; the only difference is that Where checks its arguments for validity. If Where isn't working on your sequence then perhaps you forgot to have a "using" clause to bring in the extension methods?
Eric Lippert
Sorry Eric, my bad got it. I wasnt using correct using statments
netmatrix01
+4  A: 

The ForEach extension method usually isn't worth the bother.

Eric Lippert has blogged about it, and his philosophical objection to it is that it looks like a side-effect free expression (like most Linq features) but it is actually a side-effecting imperative statement in disguise.

If you want to carry out an action for each item on a list, use the foreach statement. That's what it's for.

If you want to manipulate lists of actions, then you can do that, but then you want IEnumerable<Action>.

For the first part of your code, how about:

var errorList = GetResultRows().Where(row => row.Field<string>("status").Equals("FAILURE", StringComparison.InvariantCultureIgnoreCase)
                               .ToList();

You have a List<string> called excluded books. Use HashSet<string> instead, and you don't need to check if a string is already added to it:

var excludedBooks = new HashSet<string>();
foreach (DataRow row in errorList)
{
    if (ToUseBooksList.Contains((string)row["main_book"]))
    {
        BookCheckResults.AddRow(string.Format("Error for MainBook {0}, RiskType {1}",
                                              row["main_book"], row["risk_type"]));

        excludedBooks.Add((string)row["main_book"]);
    }
}

You can also filter the list with Where:

var excludedBooks = new HashSet<string>();
foreach (DataRow row in errorList.Where(r => ToUseBooksList.Contains((string)r["main_book"]))
{
    BookCheckResults.AddRow(string.Format("Error for MainBook {0}, RiskType {1}",
                                              row["main_book"], row["risk_type"]));

    excludedBooks.Add((string)row["main_book"]);
}
Daniel Earwicker
Hi Earwicker,you dont have Where linq extension available on IEnumerable<DataRow> hence my own filter. Can you explain how do you get Where extension of IEnumerable<DataRow> ?
netmatrix01
Extension methods are defined in classes, and classes are defined in namespaces. To make the compiler find an extension method, you need to put a using directive at the top of your source file for the namespace of the class containing the extension method. In this case: `using System.Linq;`
Daniel Earwicker