3

Couldn't think of a better title so appologies..

I'm trying to convert this method, which will retrieve all child controls of a form, to be an extension method as well as accept interfaces as inputs. So far I am up to

public IEnumerable<Control> GetAll<T>(this Control control) where T : class
{
    var controls = control.Controls.Cast<Control>();

    return controls.SelectMany(ctrl => GetAll<T>(ctrl))
                                .Concat(controls)
                                .Where(c => c is T);
}

which works fine except I need to add OfType<T>() when calling it to get access to its properties.

e.g (this == form)

this.GetAll<IMyInterface>().OfType<IMyInterface>()

I'm struggling to make the return type into a generic return type IEnumerable<T>, so that I don't have to include a OfType which will just return the same result but cast correctly.

Anyone have any suggestions?

(Changing return type to IEnumerable<T> causes the Concat to throw

Instance argument: cannot convert from 'System.Collections.Generic.IEnumerable<T>' to 'System.Linq.ParallelQuery<System.Windows.Forms.Control>'

Community
  • 1
  • 1
Sayse
  • 42,633
  • 14
  • 77
  • 146

1 Answers1

3

The problem is that Concat would want an IEnumerable<T> as well - not an IEnumerable<Control>. This should work though:

public static IEnumerable<T> GetAll<T>(this Control control) where T : class
{
    var controls = control.Controls.Cast<Control>();

    return controls.SelectMany(ctrl => GetAll<T>(ctrl))
                                .Concat(controls.OfType<T>()));
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Servy: I don't think so - `controls` is still *all* the child controls when we recurse. `OfType` is only applied to the *direct* children. – Jon Skeet Jul 03 '13 at 17:30
  • Yeah, in this case it recurses first so it would be fine, most implementations don't. – Servy Jul 03 '13 at 17:31
  • @JonSkeet - Thanks for the reply, This causes the same problem as last sentence in my question (can't convert from Control to T for Concat) – Sayse Jul 03 '13 at 17:35
  • I would only add 'where T : Control' instead of 'where T : class', since the method is only applicable to Control-derived classes anyway. – RogerN Jul 03 '13 at 17:40
  • Nevermind, the error seemed to remove itself when I rebuilt, thanks!. @RogerN, my interfaces don't derive from control – Sayse Jul 03 '13 at 17:43
  • @Sayse: An earlier version of the answer *did* have the problem, but then I moved a couple of brackets :) – Jon Skeet Jul 03 '13 at 17:45
  • @RogerN: I originally did that - then I spotted that in the question, the sample was an interface... and the method *is* applicable to interfaces that some controls may implement. – Jon Skeet Jul 03 '13 at 17:46
  • @JonSkeet - I had noticed but didn't realise there were more changes made; you missed one at the end :) Thanks again – Sayse Jul 04 '13 at 06:28