Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/4: Рейтинг темы: голосов - 4, средняя оценка - 5.00
Эксперт .NET
4432 / 2092 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
1

Есть ли в библиотеке NInject и подобных возможность сопоставить один не связанный наследованием тип к другому?

05.03.2015, 12:14. Показов 691. Ответов 4
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
В общем, написал свой контейнер сопоставления типов. Нужен был, чтобы убрать ад из кода по созданию окон настроек. Чтобы был краткий код, который создаёт окно нужного типа по типу вью модели этого окна настроек. Ранее был ад из
C#
1
2
3
4
5
6
if(settingsBase is ImSettingsVm)
{
}
else if(settingsBase is ChemicalSettingsVm)
{
}
и так ещё в нескольких местах, так как вынести в общий блок без сопоставления типов было нереально, либо я не нашёл способ, но раз я до этого додумался, то смог бы уж увидеть как это сделать проще.

Сейчас я открываю окно примерно так (там у меня ещё есть код, и код вызывающий этот метод, но это не суть):
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        internal SettingsWindowBase CreateSettingsWindow(MimicPanelObjectBase mpObject)
        {
            SettingsWindowBase window = CorrelationsLocator.SettingsWindowContainer.CreateInstance(mpObject.GetType());
            var control = GetUserControlFromSettingsWindow(window);
            if (mpObject.Settings != null)
                control.DataContext = mpObject.Settings;
            var settings = (SettingsViewModelBase)control.DataContext;
            settings.LinkedItem = mpObject;
 
            window.Owner = Application.Current.MainWindow;
            window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            window.SettingsApplied += SettingsDialog_SettingsApplied;
            window.Closing += Dialog_Closing;
 
            return window;
        }
Вот сам контейнер сопоставления:
Кликните здесь для просмотра всего текста
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
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Instrumentation;
using System.Reflection;
 
namespace XXX.Utils.Correlations
{
    /// <summary>
    /// Представляет интерфейс для контейнеров сопоставления одного типа к другому.
    /// </summary>
    /// <typeparam name="TBaseTargetType">Базовый класс для объектов сопоставления</typeparam>
    /// <typeparam name="TBaseKey">Базовый класс для ключей</typeparam>
    public abstract class СorrelationContainerBase<TBaseKey, TBaseTargetType>
        where TBaseTargetType : class
        where TBaseKey : class
    {
        private readonly Dictionary<Type, Type> _correlations;
 
        protected СorrelationContainerBase()
        {
            _correlations = new Dictionary<Type, Type>();
        }
 
        /// <summary>
        /// Зарегистрировать типы соответствия
        /// </summary>
        /// <typeparam name="TKey">Тип ключа</typeparam>
        /// <typeparam name="TTargetType">Тип соответствия ключу</typeparam>
        public void Register<TKey, TTargetType>()
        {
            _correlations.Add(typeof(TKey), typeof(TTargetType));
        }
 
        public IReadOnlyDictionary<Type, Type> RegisteredСorrelations
        {
            get { return new ReadOnlyDictionary<Type, Type>(_correlations); }
        }
 
        /// <summary>
        /// Вернуть экземпляр типа соответствия ключу.
        /// </summary>
        /// <param name="key">Ключ, по которому будет создан экземпляр типа соответствия этому ключу.</param>
        /// <exception cref="InstanceNotFoundException">Инициируется, если под переданным ключом не найден объект.</exception>
        /// <returns>Возвращает соответствие ключу.</returns>
        public Type Get(Type key)
        {
            if (_correlations.ContainsKey(key))
            {
                return _correlations[key];
            }
 
            throw new InstanceNotFoundException("Под переданным ключом не найден объект.");
        }
 
        /// <summary>
        /// Получить соответствие типу ключа в виде объекта созданного через рефлексию по типу значения.
        /// </summary>
        /// <param name="key">Ключ, по которому будет создан экземпляр типа соответствия этому ключу.</param>
        /// <exception cref="InstanceNotFoundException">Инициируется, если под переданным ключом не найден объект.</exception>
        /// <returns>Возвращает соответствие ключу.</returns>
        public TBaseTargetType CreateInstance(Type key)
        {
            if (_correlations.ContainsKey(key))
            {
                ConstructorInfo[] ctors = _correlations[key].GetConstructors();
                return (TBaseTargetType)ctors[0].Invoke(null);
            }
 
            throw new InstanceNotFoundException("Под переданным ключом не найден объект.");
        }
    }
}


Вот так я настраиваю сопоставления типов для программы. То есть я в одном месте это делаю и всё работает.

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

Я тут сократил, много удалил лишнего, так чисто чтобы было представление о чём я.
Кликните здесь для просмотра всего текста
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
99
100
101
102
103
104
using XXX.Controls.Settings;
using XXX.Utils.Correlations;
using Client.Settings.Repositories;
 
namespace Client.Correlations
{
    /// <summary>
    /// Контейнер сопоставления типов объектов мнемосхемы к окнам настроек
    /// </summary>
    public class SettingsWindowContainer : СorrelationContainerBase<MimicPanelObjectBase, SettingsWindowBase> { }
 
    /// <summary>
    /// Контейнер сопоставления вью моделей настроек к репозиториям настроек, которые имеют методы для сохранения и загрузки настроек во вью модели.
    /// </summary>
    public class SettingsRepositoriesContainer : СorrelationContainerBase<SettingsViewModelBase, ISettingsRepository> { }
 
    /// <summary>
    /// Контейнер сопоставления типов объектов мнемосхемы к вью моделям настроек
    /// </summary>
    public class SettingsVmContainer : СorrelationContainerBase<MimicPanelObjectBase, SettingsViewModelBase> { }
 
    /// <summary>
    /// Этот класс содержит в себе static свойства контейнеров сопоставлений. 
    /// </summary>
    public class CorrelationsLocator
    {
        private static SettingsWindowContainer _settingWindows;
        private static SettingsRepositoriesContainer _settingsRepositories;
        private static SettingsVmContainer _settingViewModels;
 
        /// <summary>
        /// Сопоставление объектов мнемосхемы к окнам настроек
        /// </summary>
        public static SettingsWindowContainer SettingsWindowContainer
        {
            get { return _settingWindows ?? (_settingWindows = InitSettingWindowsContainer()); }
        }
 
        /// <summary>
        /// Сопоставление репозиториев (сохранение, загрузка данных) к вью моделям окон настроек
        /// </summary>
        public static SettingsRepositoriesContainer SettingsRepositories
        {
            get { return _settingsRepositories ?? (_settingsRepositories = InitSettingsRepositories()); }
        }
 
        /// <summary>
        /// Сопоставление типов объектов мнемосхемы к вью моделям настроек
        /// </summary>
        public static SettingsVmContainer SettingViewModels
        {
            get { return _settingViewModels ?? (_settingViewModels = InitSettingsViewModels()); }
        }
 
        //Пока это лучше не использовать, чтобы не привязываться к конфигурированию объекта вью модели
        //настроек в её конструкторе. То есть, если на каком-то объекте у дозатора ИМ нет вибрации, то придётся
        //внутри конструктора класса вью модели настроек ИМ выключать вибрацию.
        //Стоит попробовать использовать библиотеку NInject и уже в ней конфигурировать создание объекта настроек
        private static SettingsVmContainer InitSettingsViewModels()
        {
            var container = new SettingsVmContainer();
 
            //Сопоставление дозаторов
            container.Register<DoserImViewModel, DoserImSettingsVm>();
            return container;
        }
 
        /// <summary>
        /// Проинициализировать все сопоставления типов
        /// </summary>
        public static void Initialize()
        {
            InitSettingWindowsContainer();
            InitSettingsRepositories();
        }
 
        private static SettingsRepositoriesContainer InitSettingsRepositories()
        {
            var container = new SettingsRepositoriesContainer();
            //Сопоставление затворов
            container.Register<LatchBaseSettingsVm, LatchBaseRepository>();
 
            //Сопоставление дозаторов
            container.Register<DoserSettingsVm, DoserSettingsRepository>();
 
            return container;
        }
 
        private static SettingsWindowContainer InitSettingWindowsContainer()
        {
            var container = new SettingsWindowContainer();
            //Сопоставление затворов
            container.Register<RotaryLatchViewModel, BaseLatchSettingsDialog>();
 
            //Сопоставление дозаторов
            container.Register<DoserImViewModel, DoserSettingsDialog>();
 
            //Сопоставление импульсных датчиков
            container.Register<LiquidCounterSensorVm, WaterMeterImpulseSettingsDialog>();
 
            return container;
        }
    }
}


Вот так я загружаю настройки. Там увидите проверку, если есть сопоставление, то берём репозиторий, если нет, то вызываем какой-то метод. Это просто переходный период от старого кода к новому, в старом просто ад был, нервы портить себе не охота, переделываю по уму.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        public void SetActualSettings(SettingsWindowBase dialog)
        {
            var control = GetUserControlFromSettingsWindow(dialog);
            SettingsViewModelBase settings = (SettingsViewModelBase)control.DataContext;
            //Чтобы сразу всё не переписывать (сохранение и загрузку настроек).
            
            if (CorrelationsLocator.SettingsRepositories.RegisteredСorrelations.ContainsKey(settings.GetType()))
            {
                ISettingsRepository repository = CorrelationsLocator.SettingsRepositories.CreateInstance(settings.GetType());
                repository.Load(settings, RegsManager.Instance.GetRegistersCopy());
            }
            else
            {
                Helper.SetActualSettings(settings);
            }
        }
Добавлено через 4 минуты
А ну и вот. Суть вопроса. Можно ли в NInject сопоставить так же типы, чтобы они не были связаны наследованием так же как у меня. Мне это нужно лишь из-за того, что в NInject есть удобный механизм настройки начальных параметров создаваемого экземпляра в NInjectModule
C#
1
2
3
4
5
6
7
8
    public class WeaponNinjectModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IWeapon>().To<Sword>()
                .WithPropertyValue("Name", name => "Кладенец");
        }
    }
Добавлено через 5 минут
И ещё. Есть такой паттерн Composition Root, вот я стремлюсь всё настраивать наверху, а потом уже брать готове где надо из контейнера сопоставления, например.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.03.2015, 12:14
Ответы с готовыми решениями:

Привести один тип к другому. Тип универсальный, параметризируется другими типами
Доброго времени суток! Прошу помощи, что-то туплю. Под вечер или вообще :) Пытаюсь привести...

Есть ли возможность подключить к текущему батнику еще один?
Я имею ввиду есть ли в CMD аналог include? То есть если допустим часть кода хранится в другом файле...

Есть ли возможность триггером проверять что записано значение в один столбец
подскажите пожалуйста а есть ли возможность триггером проверять что записано значение в один...


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

Или воспользуйтесь поиском по форуму:
4
Кодогенератор
200 / 200 / 51
Регистрация: 15.06.2011
Сообщений: 794
05.03.2015, 21:55 2
Цитата Сообщение от Casper-SC Посмотреть сообщение
Суть вопроса. Можно ли в NInject сопоставить так же типы, чтобы они не были связаны наследованием так же как у меня.
т.е. вы хотите сопоставлять разные типы? или как?
0
Master of Orion
Эксперт .NET
6098 / 4954 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
06.03.2015, 03:34 3
Casper-SC, Если у этих классов есть какие-то общие свойства, выноси их в интерфейс и бинди на на них как в примере. Я на 99,(9)% уверен, что ни один IoC не позволяет просто так рандомно присваивать любому объекту любой другой. Хотя у майков есть читерский класс-прокси, который позволяет обходить такие штуки, т.к. он имплементит ВСЕ интерфейсы и редиректит их куда надо. Название уже не вспомню, но это адский трешак. Если это внезапно нужно, то надо на пару деньков от кода отойти и подумать, ЧЯДНТ собственно
0
Эксперт .NET
4432 / 2092 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
06.03.2015, 07:25  [ТС] 4
Цитата Сообщение от hepper Посмотреть сообщение
т.е. вы хотите сопоставлять разные типы? или как?
Да.

Цитата Сообщение от Psilon Посмотреть сообщение
Если это внезапно нужно, то надо на пару деньков от кода отойти и подумать
Не, это единственный более-менее правильный вариант в данном случае. Всё это дело позволяет мне кидать в окно объект любого типа наследующего от MimicPanelObject и привязывать его к одной команде OpenSettingWindowCommand (WPF). А далее откроется окно настроек или нет зависит от того есть ли в контейнере сопоставления тип вью модели настоек для данного типа объекта наследника от MimicPanelObject.

Я думаю, тут всё нормально написано, врядли есть смысл что-то выдумывать. Самое главное, что после того как я внедрил этот механизм теперь новые настройки создавать стало в разы проще и делается это быстрее, и нужно мне лишь создать нужные классы и репозиторий для сохранения, получения настроек и сопоставить типы в контейнере.

Добавлено через 1 минуту
Ладно, я сам нагуглил, что так сделать нельзя в Ninject и подобных. Да и не особо нужно, в принципе, решил по другому проблему.
0
Кодогенератор
200 / 200 / 51
Регистрация: 15.06.2011
Сообщений: 794
06.03.2015, 10:04 5
в контейнерах поидее есть возможность добавлять типы и давать им название, чтото вроде метки, которой может выступить название сопоставляемого типа.
но думаю проще все же добавить все типы в контейнер, а сопоставить в словаре, а контейнером создавать...
0
06.03.2015, 10:04
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru