Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 20.07.2015
Сообщений: 89

Как реализовать получение компонента

26.08.2021, 03:49. Показов 1594. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте.

Есть базовый класс Component<T> в который, при наследовании передаю тип производного класса, чтобы потом кешировать в переменную.
Далее в контейнере я кеширую интерфейс IGetComponent, чтобы потом вытащить производный компонент.
Я не знаю, как связать метод GetComponent и его интерфейс, чтобы он возвращал тип Т.
Я не хочу, использовать в качестве возвращаемого типа 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
public class Container
{
 
    private Dictionary<int, IGetComponent> components = new Dictionary<int, IGetComponent>();
 
 
    public void Cache<T>(T component) where T : IGetComponent
    {
        int key = typeof(T).GetHashCode();
        if (!components.ContainsKey(key))
            components.Add(key, component);
    }
 
    public bool TryGet<T>(out T component) where T : Component<T>
    {
        IGetComponent foundComponent;
        if (components.TryGetValue(typeof(T).GetHashCode(), out foundComponent))
        {
            component = foundComponent.GetComponent();
            return true;
        }
 
        component = default(T);
        return false;
    }
}
C#
1
2
3
4
public interface IGetComponent
{
    T GetComponent();
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class Component<T> : IGetComponent where T : Component<T>
{
 
    private T cachedComponent;
 
    public void Construct()
    {
        cachedComponent = (T)this;
    }
 
    public T GetComponent()
    {
        return cachedComponent;
    }
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
26.08.2021, 03:49
Ответы с готовыми решениями:

Работа с почтой: как реализовать получение писем
Подскажите как можно на c# windows form реализовать считывания нового письма в почте?(желательно кодом)

Awesomium получение кода компонента
Как получить HTML код компонента в браузере Awesomium по которому был сделан клик мышкой.

Как реализовать получение данных из двух чисел
Всем привет. В общем, вопрос вроде простой, но я не пойму. Дано: Надо сделать штуку, куда можно положить значение int доступ к...

5
148 / 92 / 56
Регистрация: 03.02.2021
Сообщений: 284
27.08.2021, 05:30
Может быть Т можно как-то можно ограничить? Каким-нибудь базовым классом. В каких целях это создается? Что это будет?
0
0 / 0 / 0
Регистрация: 20.07.2015
Сообщений: 89
27.08.2021, 16:59  [ТС]
Идея вот в чем, любой компонент наследует класс Component<T>, где T один из типов производного класса, который будет ключом для поиска этого компонента в контейнере.
Это нужно для некой стандартизации и оптимизации.
К примеру лазерный луч взаимодействует с игроком и кубом.
Для этого я создаю базовый класс, который я буду искать в контейнере игрового объекта - LaserBeamTarget.
Его уже наследуют классы игрока (LaserBeamPlayer) и куба (LaserBeamCube).
И там, через переопределения я пищу индивидуальную логику этих объектов.
Соответственно мне нужно как-то привести LaserBeamTarget и другие подобные классы к общему виду, чтобы я мог их положить в словарь и вытянуть напрямую нужный тип (а не через апкаст).
Для этого я и написал интерфейс IGetComponent. Т и так ограничен, он должен наследоваться от Component<T>.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,111
Записей в блоге: 2
28.08.2021, 13:28
Цитата Сообщение от urbemAngeli Посмотреть сообщение
интерфейс IGetComponent
Вы случайно не пропустили <T>?
C#
1
2
3
4
public interface IGetComponent<T>
{
    T GetComponent();
}
Добавлено через 4 минуты
Цитата Сообщение от urbemAngeli Посмотреть сообщение
public abstract class Component<T>
Этого класса, воще, не понял.
Почему не так?
C#
1
2
3
4
5
public abstract class Component<T> : IGetComponent<T> where T : Component<T>
{
 
     public T GetComponent() => this;
}
Добавлено через 59 секунд
Да и какая-то бессмыслица с методом GetComponent.
Он возвращает сам объект.
Зачем такой метод?
0
0 / 0 / 0
Регистрация: 20.07.2015
Сообщений: 89
28.08.2021, 15:15  [ТС]
Вот +/- рабочий пример.
У меня есть объекты, которые состоят из контейнеров и компонентов, которые кэшируются в контейнер.
Далее есть системы, которые должны взаимодействовать с этими объектами.
Для этого, для них созданы базовые компоненты.
А уже каждый объект при необходимости расширяет эти базовые компоненты.
Так вот, при кешировании, я передаю компонент с расширенной логикой.
Однако, внутри контейнера, я вытягиваю его базовый тип, который является ключом для поиска компонента в контейнере.
Таким образом, базовый тип определен на момент постройки иерархии компонентов, для чего я и передаю Т в Component<T>.
Чтобы элементарно, мне вручную этого каждый раз не делать при кешировании + защита на дурака.
Сейчас в контейнере при кешировании, я сохраняю компонент в тип object.
Соответственно, когда я пытаюсь вытащить базовый компонент происходит апкаст, чего я и пытаюсь избежать в примере, который указан в этом вопросе.
Компилятор не дает сохранить T в словарь, либо IGetComponent<T>, поэтому я и пытаюсь сохранить ссылку на базовый компонент в Component<T> и через интерфейс пытаться его вытащить.

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public abstract class Entity
{
    public ComponentsContainer Components = new ComponentsContainer();
}
 
public class SomeCube : Entity
{
 
    // Components
    private LaserBeamCube laserBeamCube = new LaserBeamCube();
 
    private void OnEnable()
    {
        Components.Cache(laserBeamCube);
    }
}
 
 
public class SomePlayer : Entity
{
 
    // Components
    private LaserBeamPlayer laserBeamPlayer = new LaserBeamPlayer();
 
    private void OnEnable()
    {
        Components.Cache(laserBeamPlayer);
    }
}
 
 
public class LaserBeamTarget : Component<LaserBeamTarget>
{
    public virtual void OnLaserBeanEnter()
    { 
        // Лазерный луч попал в игрока
    }
}
 
public class LaserBeamPlayer : LaserBeamTarget
{
    public override void OnLaserBeanEnter()
    {
        base.OnLaserBeanEnter();
        // Убить игрока
    }
}
 
public class LaserBeamCube : LaserBeamTarget
{
    public override void OnLaserBeanEnter()
    {
        base.OnLaserBeanEnter();
        // Включить эффект свечения
    }
}
 
public class LaserBeam
{
 
    public void OnTargetEnter(Entity entity)
    {
        if (entity.Components.TryGet(out LaserBeamTarget beamTarget))
        {
            beamTarget.OnLaserBeanEnter();
        }
    }
}
 
public class ComponentsContainer
{
 
    private Dictionary<int, object> components = new Dictionary<int, object>(new FastComparable());
    private object componentTemp;
 
 
    public ComponentsContainer Cache<T>(Component<T> component) where T : Component<T>
    {
        int key = typeof(T).GetHashCode();
        if (!components.ContainsKey(key))
        {
            components.Add(key, component);
        }
        return this;
    }
 
    public bool TryGet<T>(out T result) where T : class
    {
        if (components.TryGetValue(((object)typeof(T)).GetHashCode(), out componentTemp))
        {
            result = (T)componentTemp;
            return true;
        }
 
        result = null;
        return false;
    }
}
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,111
Записей в блоге: 2
29.08.2021, 10:51
urbemAngeli, смущает ваш термин "кеширование".
Как я понял под ним вы подразумеваете какую-то коллекцию.
Коллекция эта создаётся при объявлении типов - так как обобщённый параметр должен быть известен ДО компиляции.

Если в этой коллекции будут разные типы, то она должна быть типизирована их общим предком.
Типизация object - применяется когда все эти типы могут найти общего предка только на уровне object.

Допустим, вы создали некий базовый тип ComponentContent без свойства Content.
К нему создали производные типы ComponentContent<T>, в которых есть свойство Content обобщённого типа.
И вам надо их собрать в общую коллекцию ComponentsContainer.
Вы её можете типизировать только базовым классом (или интерфейсом): ComponentsContainer: Collection<ComponentContent>.
И при работе с элементами этой коллекции вам всё равно придётся приводить их к производному типу так как по другому не получится обратить к членам объявленным в производном типе.

В каком случае имеет смысл создание базового типа.
Если у базового есть какие-то члены которые могут быть реализованы одинаковыми для всех производных или которые могут быть переопределены в производных, но использование их общее для всех типов.

Элементарный пример.
Базовый класс "животное" с общим для всех членом "вес" и виртуальным действием по умолчанию при внезапном обнаружении.
Производный тип "волк" с действиями "укусить" и "выть". В нём действие по умолчанию переопределено на вызов "укусить".
Производный тип "заяц" с действиями "драпать" и "рыть нору". В нём действие по умолчанию переопределено на вызов "драпать" .
Вы собираете коллекцию животных.
И описываете "лес".
В нём при встрече животных, вызываете базовый метод действия по умолчанию.
Производные типы сами вызовут нужный их метод.
Но если нужно вызвать действие специфичное для данного животного (например, "выть" для волка), то базовый тип необходимо сначала привести к производному.

Тоже самое для ваших компонентов.
Если есть общие члены, то чтобы использовать их без приведения к производным типам они должны быть объявлены в базовом.
Если такое невозможно, то вам не избежать приведения к производным типам.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.08.2021, 10:51
Помогаю со студенческими работами здесь

Получение указателя на объект .Net. Как это правильно реализовать?
Не понятно с первой же строки Как это всё заложить в компилятор? https://habr.com/ru/company/luxoft/blog/219619/

DatetimePichker (Как реализовать запись в БД данных с этого компонента)
Что необходимо прописать чтобы из datatimepichker (число,месяц, год) записовалось в базе и отображалось нормально.

Как реализовать FindNext в FindDialog для компонента RichEdit?
Для текстового редактора необходима кнопка &quot;Найти&quot;. Текст вводится в RichEdit. При открытии диалога FindDialog и нажатии кнопки &quot;найти...

Mdaemon (как реализовать отправку и получение)
Всем доброе время суток! Собственно вопросов несколько! 1. Сервер замечательно принимает почту, но отказывается ее отправлять...

Как реализовать быстрое получение команд с сервера с SIM900?
Всем добрый вечер. Как реализовать быстрое получение команд с сервера через SIM900? Пробовал современные gsm-сигнализации - с...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере нетипового документа выдачи шин для спецтехники с табличной частью, разработанного в конфигурации КА2. Данные берутся из. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru