2

Our project is currently using 2 ways to find a Control inside of pages. The first is to use .FindControl recursively. The other is to use LINQ like this:

(from n in Page.Controls.Cast<Control>().Descendants(c => c.Controls.Cast<Control>())
 where (n as Label != null && n.ID == "TaskIDLabel")
 select n).First() as Label;

Which uses this Extension:

static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source,
                                            Func<T, IEnumerable<T>> DescendBy)
{
    foreach (T value in source)
    {
        yield return value;

        foreach (T child in DescendBy(value).Descendants<T>(DescendBy))
        {
            yield return child;
        }
    }
}

Which of these 2 methods is better? Which is faster?

James P. Wright
  • 8,991
  • 23
  • 79
  • 142
  • 2
    Neither can be better since one is built on top of the other. – Justin Niessner Apr 04 '11 at 16:24
  • 2
    @Justin - I think the OP is asking about `FindControl` compared to the code posted in the question. – Greg Apr 04 '11 at 16:38
  • @Greg - After reading for the fourth or fifth time, I think you might be right. The wording is a tad confusing though. – Justin Niessner Apr 04 '11 at 16:48
  • @Justin - Hopefully @James will edit to clarify – Greg Apr 04 '11 at 16:59
  • The question assumes that FindControl is used recursively, i.e. checks if Control.HasChildren and calls FindControl on those Children and their Controls, etc. – James P. Wright Apr 04 '11 at 17:10
  • @James - Call FindControl on the control in question, then call FindControl on each of its children, then call FindControl on each of their children, etc? Depending on how it is implemented, you could end up with a breadth-first search or a depth-first search (probably breadth-first). The code in your question is a depth-first search. The type of search will make a difference when there is more than one control with the same name. – Greg Apr 04 '11 at 17:23
  • @Greg I'm not following, how could the controls naming have any impact on the in memory Tree relationship the .Controls property signifies? – Chris Marisic Apr 04 '11 at 17:42
  • @Chris - Consider a case in which there are two controls with the same ID on a page (which is possible as long as they are not in the same NamingContainer). A depth-first search will return the control that would be outputted to the page first, regardless of how deeply nested it is. A breadth-first search would return the control that is the least deeply nested, even if that control would be outputted to the page last. – Greg Apr 04 '11 at 17:48

3 Answers3

3

I could perform testing and find out however the stopwatch class is quick and easy to use and will tell you exactly what you need to know in about 30 seconds of effort. Let us know what you find.

http://www.dotnetperls.com/stopwatch

http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx

I suggest either adding breakpoints at the end of each stopwatch or just outputting the value using Response.Write as you're only debugging.

Edit: Have you actually noticed any performance issues or are you trying to standardise and make sure you select the correct method?

If you're using .Net 4 depending on the number of controls you could perhaps look at using the parallel extensions to iterate over the list quicker which may help. Look up "AsParallel()"

Hawxby
  • 2,746
  • 21
  • 29
1

Your code and FindControl are functionally different. They do not do the same thing.

FindControl does not perform a deep search, whereas your code does. From MSDN:

This method will find a control only if the control is directly contained by the specified container; that is, the method does not search throughout a hierarchy of controls within controls.

Which is better? It depends. If you don't know where on the page a control is, then your recursive methods can find it.

However, assume that you have two controls in a Panel (ID="MyPanel"): a custom UserControl (ID="MyControl") and a Label (ID="MyName"). If you call `MyPanel.FindControl("MyName"), you will get back the expected label in the panel. If you use your function, it will first search within MyControl for a Label with ID="MyName". Because of that, if MyControl happens to also contain a label with ID="MyName", it will be returned instead. This could be unexpected if a control happens to generate a child control with the same ID as what you are looking for.

As for performance, your method performs a deeper search so it has the potential to be a much more expensive operation.

Greg
  • 23,155
  • 11
  • 57
  • 79
1

This is a gut shot answer but I would say the IL code your hand wrote code will generate is probably very very similar to the code used by FindControl. One major difference however is Microsoft code is generally extremely optimized for the CLR taking advantage of lots of compiler hints to execute faster than most hand written code.

So I would personally use FindControl in a recursive call.

David
  • 34,223
  • 3
  • 62
  • 80
Chris Marisic
  • 32,487
  • 24
  • 164
  • 258