Как создать и передать в универсальный метод тип созданный по его имени?

144
08 ноября 2019, 18:20

Имеется несколько баз данных MS Access (файлы *.accdb) и в каждой несколько таблиц. В каждой таблице имеются как одинаковые столбцы, так и столбцы, которые имеются только у конкретной таблицы. Для каждой таблицы определён тип со свойствами аналогичными в таблице Access. Стоит задача свести все таблицы в одну таблицу MS SQL. Как решаю задачу на данный момент:

  1. Получаю список всех таблиц в БД (файле .accdb)
    oleDbConnection.GetSchema("Tables");
  2. Каждое полученное имя таблицы приводится к корректному имени класса/типа;
  3. Таблица целиком загружается в DataTable;
  4. "Конвертирую" DataTable в строго типизированный лист по типу определённому на втором шаге;

Универсальный/generic метод расширения для DataTable:

namespace RootNs {
    public static class Extensions {
        public static List<T> ToGenericList<T>(this DataTable table) where T : class, new() {
            try {
                var list = new List<T>();
                var columnNames = table.Columns
                    .Cast<DataColumn>()
                    .Select(x => x.ColumnName)
                    .ToList();
                var props = (new T()).GetType()
                    .GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var row in table.AsEnumerable()) {
                    T obj = new T();
                    foreach (string colName in columnNames) {
                        string safeClsName = colName.ToSafeName();
                        PropertyInfo prop = Array.Find(props, x => x.Name.Equals(safeClsName));
                        prop.SetValue(obj, Convert.ChangeType(row[colName], prop.PropertyType), null);
                    }
                    list.Add(obj);
                }
                return list;
            }
            catch {
                return null;
            }
        }
    }
}

Не могу найти решение: каким образом создать и передать в универсальный метод тип созданный по его имени? Может имеется какой-либо другой "безболезненный! способ конвертировать DataTable или таблицы Access в строго типизированный лист?

// к примеру, safeClsName = "SimpleClass"
string safeClsName = tableName.ToSafeName();
// Так работает
var test = dataTable.ToGenericList<SimpleClass>();
// Хотелось бы так...
var test = dataTable.ToGenericList<safeClsName>();
Answer 1

Решилось с помощью @tym32167 (Тим, ещё раз спасибо!) и следующего кода:

// oleDbDataAdapter.Fill(dataTable);
// формат "Полное.Имя.Класса, Имя.Сборки"
var extType = Type.GetType("RootNs.Extensions, RootNs", false);
var dataType = Type.GetType("RootNs.Data.SimpleClass, RootNs.Data", false);
MethodInfo method = extType.GetMethod("ToGenericList");
MethodInfo generic = method.MakeGenericMethod(dataType);
// Для статического метода первый аргумент null,
// вторым аргументом передаём массив аргументов.
var list = generic.Invoke(null, new object[]{ dataTable});
// теперь list строго типизирован

Ссылки по теме

  1. MethodInfo.Invoke(Object, Object[])
  2. MethodInfo.MakeGenericMethod(Type[])
  3. Type.GetType
  4. Связанный ответ на enSO
READ ALSO
с++ clr MSBUILD warning CA2240 - Добавьте реализацию GetObjectData

с++ clr MSBUILD warning CA2240 - Добавьте реализацию GetObjectData

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

97
WPF обработка аргументов event&#39;а во View

WPF обработка аргументов event'а во View

Пусть у меня во ViewModel имеется событие с аргументом:

100
Изменение значения из задержкой

Изменение значения из задержкой

Использую данную функцию для того чтобы поменять значение флагаТо есть имею переменную которая принимает true or false

99