Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/8: Рейтинг темы: голосов - 8, средняя оценка - 5.00
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923

Рефлексия. Копирование свойств из производных классов

22.12.2021, 21:25. Показов 1722. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть какой-то класс.
C#
1
2
3
4
public class A : B
{
    public int Age { get; set; }
}
Заведомо я не знаю какой у меня тип, знаю только то, что он наследуется от B.
Мне нужно сделать копию int-товых свойств.
Стараюсь значения его свойств скопировать примерно следующим образом:
C#
1
2
A obj = new A();
A objCopy = obj.CloneDO();
Теперь по коду.
target -- это я заранее ищу подходящий конструктор. Упущу этот момент, но в спойлере оставлю код.
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        ///<inheritdoc cref="CloneDO{T}(T, Func{T, T})"/>
        public static T CloneDO<T>(this T dObj)
            where T : B
        {
            Func<T> constructor = ConstractorExtantions<T>.GetConstructor(dObj.GetType());
            T clone = constructor();
            if (clone == null)
            {
                throw new Exception("Не удаётся создать новый экземпляр этого типа.");
            }
 
            dObj.CopyDpTo(clone);
 
            return clone;
        }
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
        private class ConstractorExtantions<T> where T : B
        {
            private static readonly Dictionary<Type, Func<T>> constructors = new Dictionary<Type, Func<T>>();
 
            private static readonly Type[] emptyTypes = new Type[0];
 
            public static Func<T> GetConstructor(Type type)
            {
                if (!constructors.TryGetValue(type, out var func))
                {
                    var constructor = type.GetConstructor
                        (
                            BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly,
                            null, emptyTypes, null
                        );
                    if (constructor == null)
                    {
                        func = new Func<T>(() => default(T));
                    }
                    else
                    {
                        DynamicMethod dynamic = new DynamicMethod(string.Empty,
                                    type,
                                    Type.EmptyTypes,
                                    type);
                        ILGenerator il = dynamic.GetILGenerator();
 
                        il.DeclareLocal(type);
                        il.Emit(OpCodes.Newobj, constructor);
                        il.Emit(OpCodes.Stloc_0);
                        il.Emit(OpCodes.Ldloc_0);
                        il.Emit(OpCodes.Ret);
 
                        func = (Func<T>)dynamic.CreateDelegate(typeof(Func<T>));
                    }
                    constructors.Add(type, func);
                }
                return func;
            }
        }

В общем и целом target -- конечный результат скопированного объекта (а точнее его int-овых свойств).
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
        public static void Copy<T>(this T source, T target)
            where T : B
        {
            Dictionary<string, int> properties = new Dictionary<string, int>();
            ////// Looking for int properties by Reflex.
            {
                var propEnumerator = source.GetType().GetTypeInfo().DeclaredProperties.GetEnumerator();
                while (propEnumerator.MoveNext())
                {
                    if (propEnumerator.Current.PropertyType == typeof(int)
                        /*&& propEnumerator.Current.CanWrite*/)
                    {
                        string fullName = propEnumerator.Current.Name;
                        properties.Add(fullName, (int)propEnumerator.Current.GetValue(source));
                    }
                }
            }
            ////// Deliting properties that are not in another object.
            {
                var propEnumerator = target.GetType().GetTypeInfo().DeclaredProperties.GetEnumerator();
                while (propEnumerator.MoveNext())
                {
                    string fullName = propEnumerator.Current.Name;
                    if (propEnumerator.Current.PropertyType == typeof(int) && !properties.TryGetValue(fullName , out var value)
                        /*&& propEnumerator.Current.CanWrite*/)
                    {
                         // тут обработка не касающаяся темы.
                    }
                }
            }
В итоге я получаю все свойства типа int из класса A, но из класса B -- ничего.
Как мне пройтись по всем другим классам и сделать то же самое?
Добавлено через 11 минут
Не дочерние, а классы наследники*
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.12.2021, 21:25
Ответы с готовыми решениями:

Наследование классов. Копирование производных классов
Здравствуйте всем, у меня такой вопрос: написал код #include &quot;stdafx.h&quot; class A //Создаем класс А { int mA; ...

Рефлексия. Нужно красивое решение для работы в производных классах со статическими членами базового класса
Демонстрационный код для объяснения задачи. Базовый класс и два производных от него: public class BaseClass&lt;T&gt; { ...

Рефлексия конструкторы базовых классов
Здравствуйте! Подскажите, пожалуйста, почему метод Type.GetConstructors() не возвращает конструкторы базовых классов, почему рефлексия не...

6
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
22.12.2021, 21:28
limeniye, не совсем понял решаемую задачу.
Вам надо создать клон экземпляра или получить в какую-то коллекцию названия только свойств и их значения?
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
22.12.2021, 21:39  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вам надо создать клон экземпляра или получить в какую-то коллекцию названия только свойств и их значения?
Копирование можно сделать через MemberwiseClone, но помимо обычного копирования свойств
C#
1
2
3
        private static readonly Func<object, object> memberwiseClone
            = (Func<object, object>)(typeof(object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance))
            .CreateDelegate(typeof(Func<object, object>));
я делаю ещё некие манипуляции с этими свойствами.

Не по теме:


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



Допустим класс B выглядит следующим образом
C#
1
2
3
4
class B : C
{
    int Value { get; set; }
}
Но выше приложенный код найдёт только свойства, которые находятся в классе A, то есть Age. По типу B,C...Z оно не проходится. "Берёт только то, что на поверхности лежит".
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
22.12.2021, 23:11
limeniye, не тестировал, но вроде такой метод расширения должен работать для публичных свойств экземпляра:
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
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
 
namespace ****
{
    /// <summary>Методы расширения.</summary>
    public static partial class ExtensionMethods
    {
        public static ReadOnlyDictionary<string, T> GetPropertiesValues<T>(this object obj)
        {
            Type typeT = typeof(T);
            Type type = obj.GetType();
            var properties = type.GetProperties();
            Dictionary<string, T> values = new Dictionary<string, T>();
            foreach (var property in properties)
            {
                if (typeT.IsAssignableFrom(property.PropertyType))
                {
                    values.Add(property.Name, (T)property.GetValue(obj));
                }
            }
 
            return new ReadOnlyDictionary<string, T>(values);
        }
    }
}
Добавлено через 2 минуты
Вытягивает значение всех свойств указанного типа и производных от него.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
DeclaredProperties.
Это только свойства объявленные в этом типе.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
23.12.2021, 18:34
limeniye, примеры использования:
C#
1
2
3
    Point2D point = new Point2D(12.34, 56.78);
    var props = point.GetPropertiesValues<double>();
    Console.WriteLine(string.Join(Environment.NewLine, props.Select(p => $"{p.Key}={p.Value}")));
КонсольX=12,34
Y=56,78


C#
1
2
3
4
5
6
7
8
9
    public class ExampleA
    {
        public string Name { get; set; }
    }
 
    public class ExampleB : ExampleA
    {
        public int Id { get; set; }
    }
C#
1
2
3
4
5
6
7
8
9
10
    ExampleB b = new ExampleB() { Name = "First", Id = 123 };
    var props = b.GetPropertiesValues<string>();
    Console.WriteLine(string.Join(Environment.NewLine, props.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
    var props1 = b.GetPropertiesValues<int>();
    Console.WriteLine(string.Join(Environment.NewLine, props1.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
    var props2 = b.GetPropertiesValues<object>();
    Console.WriteLine(string.Join(Environment.NewLine, props2.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
КонсольName=First

Id=123

Id=123
Name=First
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
23.12.2021, 20:22  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вытягивает значение всех свойств указанного типа и производных от него.
Нет, что-то тут не то.
Я не вижу нужных мне свойств. На выходе я получаю только свойства из этого класса.

В этом моменте
C#
1
var properties = type.GetProperties();
я получаю 115 свойств, 20 из которых из начального класса, остальные -- из классов-родителей.
Но в этих 115 свойств я не вижу нужных мне типов из других классов.

Пример:
C#
1
2
3
4
5
6
7
8
9
10
11
class B : C
{
    int Age { get; set; }
    int Width { get; set; }
    string Name { get; set; }
}
class A : B
{
    int Value { get; set; }
    string Surname {get; set; }
}
Допустим я ищу все int'ы.
На моменте
C#
1
var properties = type.GetProperties();
получаю следующий список --
Code
1
{ Value, Surname, Name }
А после отсеивания ненужных типов я получаю просто:
Code
1
{ Value }
Добавлено через 4 минуты
То есть я получа Name из класса-родителя, но я не получа Width и Age, котрые, собственно, мне и нужны.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,110
Записей в блоге: 2
23.12.2021, 21:11
Лучший ответ Сообщение было отмечено limeniye как решение

Решение

limeniye, ошибки:
1) возможно вы как-то не так скопировали мой метод.
Скопируйте класс полностью, не изменяя его.

2) Метод вытягивает значения только ПУБЛИЧНЫХ свойств экземпляра.


Пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    class C
    {
        public int Id { get; set; } = 123;
    }
 
    class B : C
    {
        public int Age { get; set; } = 4;
        public int Width { get; set; } = 5;
        public string Name { get; set; } = "qwerty";
    }
    class A : B
    {
        public int Value { get; set; } = 67;
        public string Surname { get; set; } = "asdff";
    }
C#
1
2
3
4
5
6
7
8
9
10
    A a = new A();
    var props = a.GetPropertiesValues<string>();
    Console.WriteLine(string.Join(Environment.NewLine, props.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
    var props1 = a.GetPropertiesValues<int>();
    Console.WriteLine(string.Join(Environment.NewLine, props1.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
    var props2 = a.GetPropertiesValues<object>();
    Console.WriteLine(string.Join(Environment.NewLine, props2.Select(p => $"{p.Key}={p.Value}")));
    Console.WriteLine();
КонсольSurname=asdff
Name=qwerty

Value=67
Age=4
Width=5
Id=123

Value=67
Surname=asdff
Age=4
Width=5
Name=qwerty
Id=123
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.12.2021, 21:11
Помогаю со студенческими работами здесь

Создание производных классов
Пожалуйста, помогите понять, в чем проблема. Не могу разобраться уже несколько дней. Всё делалось по примеру, но мой вариант не работает....

Создание производных классов
У меня есть два класса. Нужно создать базовый класс Pair с виртуальными арифметическими операциями. И сделать классы FazzyNumber и Fraction...

Создание производных классов
есть две задачи: Дан класс class base{ public virtual void iam{cout«' base \n';} } Определить производный класс child и в нем...

Сравнение производных классов
Друзья! Пусть у меня есть базовый класс S. У него есть два наследника A и B. Как мне скидывать, например в set, указатели (шаредпэтэры...

Массив производных классов
Скажите пожалуйста или дайте ссылку/пример, где можно почитать (мною найдено не было) как на Паскале реализовать &quot;массив объектов, в...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru