Отражение - собирать элементы управления WinForm - PullRequest
0 голосов
/ 07 февраля 2020

ОПИСАНИЕ : Я хочу взять все доступные элементы управления из более чем 1000 winforms из многих сборок. Я не хочу иметь большие усилия по рефакторингу. (Небольшой инструмент, причина для внутреннего использования)

ЧТО УЖЕ СДЕЛАНО : Получил все сборки, и из каждой сборки взял все типы, которые мне интересны, через type.IsSubclassOf(selectedType).

ИНФОРМАЦИЯ ОБ ОСНОВНОМ ПРОЕКТЕ : Многие классы имеют конструкторы по умолчанию, некоторые нет, другие ссылаются на другие базовые классы. Структура проекта не столь оптимальна, потому что это продукт, который разрабатывался в течение 15 лет.

ПРОБЛЕМА : Я пытался взять все элементы управления с помощью отражения, используя Activator.CreateInstance(type), но для многих классов Я взял необработанные исключения или другие исключения базового класса, которые не были управляемы. Другой проблемой, с которой я столкнулся во время этой процедуры, был кастинг. Я также пытался FormatterServices.GetUninitializedObject(type), но я не нашел, как или можно ли взять элементы управления.

ВОПРОС : можно ли собрать элементы управления winForm 'Form' с такой структурой без особых усилий? Какие могут быть различные способы добиться этого?

enter image description here enter image description here

ПРИМЕР КОДА

static List<AssemblyName> _assemblyList=new List<AssemblyName>();
static List<Type> _typeList = new List<Type>();
static List<Control> _controlList = new List<Control>();

private static void getFormTypes()
{
    foreach (AssemblyName assemblyName in _assemblyList)
    {
        Assembly assembly = Assembly.Load(assemblyName);
        foreach (Type type in assembly.GetTypes())
        {
            if (type.IsSubclassOf(typeof(Form)))
            {
                _typeList.Add(type);
            }
        }
    }
}

private static void getAllControlsFromFormTypes()
{
    foreach (Type type in _typeList)
    {
        object instance = default;

        if (HasValidConstructor(type))
        {
            instance = Activator.CreateInstance(type);//Here I have unhandled exceptions from base classes during constructor invoking
            GetValidControls((Control)instance);
        }
    }
}


private static void GetValidControls(Control container)
{
    foreach (Control control in container.Controls)
    {
        GetValidControls(control);

        if (!string.IsNullOrEmpty(control.Name) && !string.IsNullOrEmpty(control.Text))
        {
            _controlList.Add(control);
        }
    }
}

public static bool HasValidConstructor(Type t) => t.IsValueType || !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null;```

1 Ответ

1 голос
/ 07 февраля 2020

Когда вы удаляете элемент управления в форме, конструктор создает поле элемента для элемента управления. Если вы не изменили свойство GenerateMember, чтобы изменить это поведение, или не использовали мастера форм данных, которые создают метки без переменных-членов, тогда вы можете получить все элементы управления, используя эти поля-члены, без создания экземпляров форм.

Для каждой сборки вы можете получить список форм и элементов управления без создания экземпляра следующим образом:

IEnumerable<Type> GetFormsAndControlsTypes(Assembly assembly)
{
    var forms = assembly.GetTypes()
        .Where(type => typeof(Form).IsAssignableFrom(type));

    var controls = forms.SelectMany(
        form => form.GetFields(
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
            .Where(field => typeof(Control).IsAssignableFrom(field.FieldType))
            .Select(field => field.FieldType));

    return forms.Concat(controls).Distinct().ToList();
}

Однако в целом такая задача выглядит как анализ кода, а не как задача времени выполнения.

...