Найти компоненты в форме окна С# (не управляет)

Я знаю, как найти и собрать список всех элементов управления, используемых в Windows Form. Что-то вроде этого:

static public void FillControls(Control control, List<Control> AllControls)
{
    String controlName = "";
    controlName = control.Name;

    foreach (Control c in control.Controls)
    {
        controlName = c.Name;
        if ((control.Controls.Count > 0))
        {
            AllControls.Add(c);
            FillControls(c, AllControls);
        }
    }
}

Однако эта функция не извлекает невизуальные компоненты в нижней части формы, такие как HelpProvider, ImageList, TableAdapters, DataSets и т.д.

Есть ли способ получить список этих компонентов?

Edit:

Спасибо @HighCore за то, что указали, что я использую System.ComponentModel.Component вместо этого в подобной функции, я получаю список с такими компонентами, как ImageList, Справочный провайдер и BindingSource. Тем не менее, я все еще пропускаю из этого списка TableAdapters и DataSets. Я полагаю, потому что те наследуют непосредственно от Object.

Пожалуйста. Не относитесь ко мне к более старым сообщениям, которые показывают аналогичную функцию для моего, и это только получает список элементов управления.

Изменить: Почему отрицательные голоса? На этот вопрос никогда не отвечали!

Ответ 1

Удивительно, но единственный способ сделать это - через отражение.

private IEnumerable<Component> EnumerateComponents()
{
    return from field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
           where typeof (Component).IsAssignableFrom(field.FieldType)
           let component = (Component) field.GetValue(this)
           where component != null
           select component;
}

Ответ 2

Все элементы управления, созданные через конструктор, должны иметь закрытое поле, называемое "компоненты" типа IContainer. Вы можете использовать отражение, чтобы получить значение этого поля, если оно существует, а затем выполнить итерацию по компонентам.

Этот метод отличается от другого ответа тем, что он будет возвращать только компоненты, добавленные в форму с использованием конструктора, в отличие от всех полей, которые могут быть преобразованы как Компонент.

    public IEnumerable<Component> GetComponents(Control c)
    {
        FieldInfo fi = c.GetType()
            .GetField("components", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        if (fi?.GetValue(c) is IContainer container)
        {
            return container.Components.OfType<Component>();
        }
        else
        {
            return Enumerable.Empty<Component>();
        }
    }