Question

I have code below to bind active directory entries to an ASP.NET TreeView. It is working fine but I would like to achieve the same results using LINQ or Lambda expressions. My manager does not want to use foreach loop any of place in our application. So how can we bind these entries into treeview by using LINQ.

Here is my page load foreach code:

foreach (DirectoryEntry firstChild in OUs)
{
    if (firstChild.SchemaClassName.Contains("organizationalUnit"))
    {
        TreeNode Node = new TreeNode(firstChild.Name.Substring(firstChild.Name.IndexOf('=') + 1));
        rootNode.ChildNodes.Add(Node);
        AddNodes(firstChild, Node);
    }
}

TreeView1.Nodes.Add(rootNode);

Recursive function to bind the tree node values:

private void AddNodes(DirectoryEntry entry, TreeNode node)
{
    foreach (DirectoryEntry child in entry.Children)
    {
        TreeNode childNode = new TreeNode(child.Name.Substring(child.Name.IndexOf('=') + 1));
        node.ChildNodes.Add(childNode);
        this.AddNodes(child, childNode);           
    }
}

Please could anyone suggest how to achieve the same result with LINQ or Lambda expression.

Was it helpful?

Solution

Treating this as a kind of code-golf, the following gives an idea as to how you can approach the problem from a functional mindset, where you try and 'flow' the results of one function through another (which is presumably what your manager is after).

Some changes are possible:

  • Replacing the if with a filter predicate on the set
  • By changing the recursive method AddNodes() to return the node, it can be used in a fluent style.

There also an obvious design mismatch given that TreeViews weren't designed with FP in mind, and instead encourage iterative mutation to the tree to build it up. Sadly, TreeNodeCollection has no direct setter, nor an AddRange. So the horrid ForEach mutation seems necessary.

As a result, it is moot whether this constitutes any kind of improvement to your imperative original solution (Unless the rest of your code base is maintained by a bunch of F# or Haskell programmers). A TreeView which can be constructed in one projection would IMO be a pre-requisite for the switch to this approach.

// Recursive Funcs need to be forward-declared
Func<DirectoryEntry, TreeNode, TreeNode> addNodes = null;
addNodes = (entry, node) =>
    {
        entry.Children
           .Cast<DirectoryEntry>()
           .ToList() // Needed for ForEach
           .ForEach(
             child =>
               node.ChildNodes.Add(
                     addNodes(child,
                    new TreeNode(child.Name.Substring(child.Name.IndexOf('=') + 1)))));
        return node;
    };

OUs.Where(ou => ou.SchemaClassName.Contains("organizationalUnit"))
    .ToList()
    .ForEach(ou =>
            rootNode.ChildNodes.Add(addNodes(ou, 
                 new TreeNode(ou.Name.Substring(ou.Name.IndexOf('=') + 1)))));
treeView1.Nodes.Add(rootNode);

OTHER TIPS

The thing is: LINQ is used for collections selection, not for performing recursive loops. You can shorten your code

foreach(var dirEntry in OUs.Where(ou => ou.SchemaClassName.Contains("organizationalUnit")))
{
    AddNodes(dirEntry, rootNode);
}

TreeView1.Nodes.Add(rootNode);

3 lines instead of 6, but that's IMO the only reasonable modification you can do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top