С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
26 / 11 / 1
Регистрация: 20.05.2015
Сообщений: 211
1

Рефлексия обобщенных коллекций для вызова методов при неизвестном типе

08.06.2022, 18:01. Показов 886. Ответов 23

Author24 — интернет-сервис помощи студентам
Если вкратце: Использую Entity Framework в котором используется множество коллекций сущностей DbSet;

Все коллекции разные, но почти все имеют общую суть (обрабатываются одинаково).

Вопрос, как мне через рефлексию сделать возможным работу со всеми коллекциями одним кодом (типа Load, преобразование в таблицу, Save и прочие непотребства). Можно, конечно, каждый раз все таблицы перечислять, но как-то это не по програмерски.

Абстрактный нерабочий пример (так как в метод расширение Load надо передать обобщение с аргументом):

C#
1
2
3
4
5
6
7
8
9
 public class MyDbContext: DbContext
    {
        public DbSet<a> A{ get; set; }
        public DbSet<b> B{ get; set; }
        public DbSet<c> C{ get; set; }
        public DbSet<d> D{ get; set; }
        public DbSet<e> E{ get; set; }
// и т.д.
   }
C#
1
2
3
4
5
6
7
8
9
10
11
               var props = typeof(MyDbContext).GetProperties();
                foreach (var prop in typeof(MyDbContext).GetProperties())
                {                    
                    if (prop.PropertyType.Name == "DbSet`1")
                    {
                        Type? type = prop.PropertyType.GenericTypeArguments[0]; //Вот его бы как-нибудь в обобщение передать как аргумент.
                        var source = prop.GetValue(ap);
                        if (source != null)
                            EntityFrameworkQueryableExtensions.Load(source); //просто расширение для примера, тут могут быть иные действия, но все они требуют тип аргумента
                    }
                }
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.06.2022, 18:01
Ответы с готовыми решениями:

Рефлексия обобщенных типов
Допустим созали какой то тип, оформили как библиотеку Class Library скомплировали, затем загрузили...

Алгоритм для вызова методов с массива
Заранее извините за возможную не точною формулировку допустим.. у меня есть массив экземпляров...

Специальные методы для вызова необъявленных методов объекта
Существуют ли в Java функции аналогичные __call() в php, т.е. если я обращаюсь к несуществующему...

Рефлексия методов и конструкторов
Задание: нужно получить методы и конструкторы (с аргументами) из класса предметной области и класса...

23
26 / 11 / 1
Регистрация: 20.05.2015
Сообщений: 211
20.11.2022, 14:21  [ТС] 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Элд Хасп Посмотреть сообщение
werymag, рефлексия здесь допустма.
Пример https://stackoverflow.com/a/564373/13349759
В этом примере надо только добавить сохранение полученных рефлексией данных.
И следующий раз использовать не рефлексию, а уже сохранённые данные.
Сеттеры и Геттеры свойств хранить как делегаты Action и Func<object>.
Ну в целом я это уже и так реализовал своими корявыми руками . Это-то относительно просто.
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
      public List<T> TableToList<T>(DataTable table)
            where T : new()
        {
            List<T> elements = new List<T>();           
            foreach (DataRow row in table.Rows)
            {
                T elem = new();
                elements.Add(elem);
                foreach (var prop in typeof(T).GetProperties())
                    if (table.Columns.Contains(prop.Name.Replace('_', ' ')))
                    {
                        var value = row[prop.Name.Replace('_', ' ')];
                        prop.SetValue(elem, value is DBNull ? null : value);
                    }
            }
            return elements;
        }
        public WellDataTable ListToTable<T>(TableDataSet set, List<T> objectsList)
        {
 
            WellDataTable table = new WellDataTable(typeof(T).Name.Replace('_', ' '), set, true);
            var properties = typeof(T).GetProperties();
 
            foreach (PropertyInfo property in properties)
            {
                WellDataColumn newColumn = new WellDataColumn(
                    property.Name.Replace('_', ' '),
                    Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType);
                table.Columns.Add(newColumn);
            }
 
            foreach (T objectDB in objectsList)
            {
                DataRow row = table.NewRow();
                table.Rows.Add(row);
                foreach (PropertyInfo property in properties)
                    row[property.Name.Replace('_', ' ')] = property.GetValue(objectDB) ?? DBNull.Value;
 
            }
            return table;
        }

Можно, конечно попробовать эту библиотеку мета программирования, но что-то лень пока для столь малой задачи ...
Думал может есть более элегантные способы без 20


Честно признаться не понимаю этих претензий к скорости работы рефлексии с в контексте работы с DataTable с её распаковкой/запаковкой типов. Мне кажется заполнение средних размеров таблицы всё равно будет на порядок дольше, чем работа рефлексии (возможно ошибаюсь).

В целом то всё равно в обоих периметрах по ссылке используются джейнерики, то есть всё равно надо явно указать тип членов списка, что опять приводт к необходимости использования 20 строк кода в место одной (о ужас ), то есть к тому же, что я написал выше (правда согласен, надо вытащить конвертацию)
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В каждой таблице только отражение одной сущности?
Или разные строки нужно в разные сущности отражать?
Строго одной, таблицы и сущностью полностью одинаковые, у меня даже скриптик есть, который из всех таблиц генерирует класс со всеми сущностями, эдакий TableFirst
0
Модератор
Эксперт .NET
15858 / 11005 / 2855
Регистрация: 21.04.2018
Сообщений: 32,348
Записей в блоге: 2
20.11.2022, 15:26 22
Цитата Сообщение от werymag Посмотреть сообщение
public List<T> TableToList<T>(DataTable table)
Если правильно понял.
Вы получаете в DataTable данные одной таблицы БД.
Соответственно, TableName должен содержать имя этой таблицы.
И по имени таблицы из DbContext можно получить тип сущности для этой таблицы.

То есть в обобщённом методе, как мне кажется, нет необходимости.
Так же раз этот тип будет из DdContext, то он гарантированно содержит конструктор по умолчанию.

Цитата Сообщение от werymag Посмотреть сообщение
WellDataTable table = new WellDataTable(typeof(T).Name.Replace('_', ' '), set, true);
Вот здесь бы я предпочёл сохранить имя таблицы БД в оригинале.
Его нужно или явно передать, или получить из атрибута сущности.
Замена символов, возможно, нужна для Представления, ну там и стоит это преобразование проводить.

Добавлено через 5 минут
Цитата Сообщение от werymag Посмотреть сообщение
List<T> objectsList
Здесь нужен IList, или IEnumerable без дженерика.
И рефлексией проверять, есть дженерик или нет.
И если есть, то сущность это DbContext или нет.
Для сущности DbContext получать имя таблицы из DbContext.
Для остальных - проверять наличие атрибута [Table], для свойств наличие атрибута [Column].

Добавлено через 2 минуты
Цитата Сообщение от werymag Посмотреть сообщение
В целом то всё равно в обоих периметрах по ссылке используются дженерики,
От дженериков лучше избавиться.
Выше описал примерный путь.
Сделать нужно на "чистой рефлексии".
Можно для удобства использования потом добавить перегрузки с дженериками.

Добавлено через 6 минут
TableToList, ListToTable обычно не указывается из чего конвертируется.
И лучше сделать как статические методы расширения.
То есть более типично: public static IList ToList(this DataTable table) и public static WellDataTable ToTable(this IEnumerable objects).

Если добавится проверка согласованности с DbContext, то тогда можно передавать дженериком тип DbContext.
1
26 / 11 / 1
Регистрация: 20.05.2015
Сообщений: 211
20.11.2022, 16:25  [ТС] 23
Цитата Сообщение от Элд Хасп Посмотреть сообщение
То есть в обобщённом методе, как мне кажется, нет необходимости.
Так же раз этот тип будет из DdContext, то он гарантированно содержит конструктор по умолчанию.
Мозг плавиться...
такой вариант ругается, что нельзя динамически создать DBSet (WellID - это базовый класс для всех таблиц с полями имя и ID)

C#
1
2
3
4
      Type typeDBSet = this.GetType().GetProperty(table.TableName.Replace(' ', '_')).PropertyType;
         Type entityType = typeDBSet.GetGenericArguments().Single();
 
          DbSet<WellID>? elements = Activator.CreateInstance(typeDBSet) as DbSet<WellID>;
Такой вариант с форума ругается на неоднозначность совпадения метода с именем Set....

C#
1
2
3
4
5
6
7
8
            Type typeDBSet = this.GetType().GetProperty(table.TableName.Replace(' ', '_')).PropertyType;
            Type entityType = typeDBSet.GetGenericArguments().Single();
 
            MethodInfo? dbSetMethodInfo = typeof(DbContext).GetMethod("Set");
            dynamic dbSet = dbSetMethodInfo.MakeGenericMethod(entityType).Invoke(this, null);
            dynamic Rec = Activator.CreateInstance(entityType);
            Rec.active = true;
            dbSet.Add(Rec);
В целом я тут подумал... 20 строчек кода с джейнериком не так уж плохо, как-то прям больно всё это выглядит

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Здесь нужен IList, или IEnumerable без джененрика.
И рефлексией проверять, есть дженерик или нет.
И если есть, то сущность это DbContext или нет.
Для сущности DbContext получать имя таблицы из DbContext.
Для остальных - проверять наличие атрибута [Table], для свойств наличие атрибута [Column].
Ага, спасибо большое, поправлю, да это я на ходу между написаниями сообщений сделал, как мысль в голову легла. Надо, конечно, править.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
TableToList, ListToTable обычно не указывается из чего конвертируется.
Спасибо, буду знать!

Но в целом задача, конечно, не стоит затраченных усилий, уже больше спортивный интерес .
0
Модератор
Эксперт .NET
15858 / 11005 / 2855
Регистрация: 21.04.2018
Сообщений: 32,348
Записей в блоге: 2
20.11.2022, 16:34 24
Цитата Сообщение от werymag Посмотреть сообщение
задача, конечно, не стоит затраченных усилий, уже больше спортивный интерес
Я так и понял.
Рефлексия чаще всего и используется в библиотеках на целенных на широкое использование во избежание явных зависимостей.

Цитата Сообщение от werymag Посмотреть сообщение
Мозг плавиться...
такой вариант ругается, что нельзя динамически создать DBSet
Вы имя таблицы хотите получить?

Если да, то это данные БД. А с БД работает DbContext, а не DbSet.
DbSet для конкретной БД подготавливается DbContext'ом.

Поэтому вам нужно передавать SomeMethod<TDbContext>(....) where TDbContext : DbContext, new().
1
20.11.2022, 16:34
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
20.11.2022, 16:34
Помогаю со студенческими работами здесь

Наследование,переопределение методов[рефлексия]
Раньше я практически не сталкивался с рефлексией, но теперь появилась острая проблема .Загружаю...

Какой алгоритм выбрать для меньшего кол-во вызова api-методов?
Всем привет:) Мне нужно сделать интеграцию моего сервиса с другим. Что у меня есть: сторонние api...

Рефлексия методов с неизвестным массивом параметров
Здравствуйте! Подскажите, как мне передать параметры в getMethod, для выполнения этого метода через...

Рефлексия. Вывод списка методов, свойств
Здравствуйте. Задание по рефлексии, я в ней вообще не разбираюсь. Итак, задание следующее: Я...

Рефлексия, можно ли получить имена параметров методов
Типы параметров метода(и их количество) можно узнать, используя рефлексию. Возможно ли узнать...

Для чего нужна рефлексия при подключении к БД?
Здравствуйте, Объясните пожалуйста для чего нужно при подключении к БД перед созданием...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
24
Ответ Создать тему
Новые блоги и статьи
Книги и учебные ресурсы по C#
InfoMaster 08.01.2025
Базовые учебники и руководства Одной из лучших книг для начинающих является "C# 10 и . NET 6 для начинающих" Эндрю Троелсена и Филиппа Джепикса . Книга последовательно раскрывает основные концепции. . .
Что такое NullReferenceEx­­­ception и как исправить?
InfoMaster 08.01.2025
NullReferenceException - одно из самых распространенных исключений, с которым сталкиваются разработчики на C#. Это исключение возникает при попытке обратиться к членам объекта (методам, свойствам или. . .
Что такое Null Pointer Exception (NPE) и как это исправить?
InfoMaster 08.01.2025
Null Pointer Exception (NPE) - это одно из самых распространенных исключений в Java, которое возникает при попытке использовать ссылку на объект, значение которой равно null. Это исключение относится. . .
Русский язык в консоли C++
InfoMaster 08.01.2025
При разработке программ на C++ одной из частых проблем, с которой сталкиваются русскоязычные программисты, является корректное отображение кириллицы в консольных приложениях. Эта проблема особенно. . .
Telegram бот на C#
InfoMaster 08.01.2025
Разработка ботов для Telegram стала неотъемлемой частью современной экосистемы мессенджеров. C# предоставляет мощный и удобный инструментарий для создания разнообразных ботов, от простых. . .
Использование GraphQL в Go (Golang)
InfoMaster 08.01.2025
Go (Golang) является одним из наиболее популярных языков программирования, используемых для создания высокопроизводительных серверных приложений. Его архитектурные особенности и встроенные. . .
Что лучше использовать при создании класса в Java: сеттеры или конструктор?
Alexander-7 08.01.2025
Вопрос подробнее: На вопрос: «Когда одновременно создаются конструктор и сеттеры в классе – это нормально?» куратор уточнил: «Ваш класс может вообще не иметь сеттеров, а только конструктор и геттеры. . .
Как работать с GraphQL на TypeScript
InfoMaster 08.01.2025
Введение в GraphQL и TypeScript В современной разработке веб-приложений GraphQL стал мощным инструментом для создания гибких и эффективных API. В сочетании с TypeScript, эта технология. . .
Счётчик на базе сумматоров + регистров и генератора сигналов согласования.
Hrethgir 07.01.2025
Создан с целью проверки скорости асинхронной логики: ранее описанного сумматора и предополагаемых fast регистров. Регистры созданы на базе ранее описанного, предполагаемого fast триггера. То-есть. . .
Как перейти с Options API на Composition API в Vue.js
BasicMan 06.01.2025
Почему переход на Composition API актуален В мире современной веб-разработки фреймворк Vue. js продолжает эволюционировать, предлагая разработчикам все более совершенные инструменты для создания. . .
Архитектура современных процессоров
inter-admin 06.01.2025
Процессор (центральный процессор, ЦП) является основным вычислительным устройством компьютера, которое выполняет обработку данных и управляет работой всех остальных компонентов системы. Архитектура. . .
История создания реляционной модели баз данных, правила Кодда
Programming 06.01.2025
Предпосылки создания реляционной модели В конце 1960-х годов компьютерная индустрия столкнулась с серьезными проблемами в области управления данными. Существовавшие на тот момент модели данных -. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru