Страницы

Поиск по вопросам

вторник, 9 июля 2019 г.

Получение типа из подкласса. Полиморфизм C#

Доброго времени суток, столкнулся с такой проблемой. Есть абстрактный класс ViewModel, который содержит логику добавления данных в коллекцию для отображения в GUI.
public abstract class ViewModel {
public ObservableCollection Data { get; set; } protected abstract IModel createObject(SqlDataReader reader);
protected void selectData(string query) { // ... // Логика получения reader // ... IModel item = this.createObject(reader); this.Data.Add(item); } }
Также есть классы моделек, все они реализую интерфейс IModel, код приводить не буду, в нем нет необходимости. Класс реализующий ViewModel выглядит так:
public class UsersViewModel : ViewModel {
public UsersViewModel() { string query = "SELECT TOP 300 * FROM users ORDER BY reputation DESC"; this.selectData(query); }
protected override IModel createObject(SqlDataReader reader) { return new User(reader); } }
Проблема собственно в методе createObject. Во всех подклассах он делает одну единственную вещь: возвращает экземпляр класса модели. Мне бы хотелось от него избавится. И сделать так, что бы в абстрактном классе ViewModel метод selectData сам создавал тот объект модели, какой нужно, а какой именно, он бы узнавал из подкласса. Метод должен выглядеть примерно так:
protected void selectData(string query) { // Логика получения reader IModel item = new Тип_Модели_из_подкласса(reader); this.Data.Add(item); }
Кажется мне, что проблему можно решить с помощью обобщений, но не знаю как. Или создать в подклассе свойство, которое будет уточнять какую именно реализацию интерфейса IModel нужно использовать. Как мне это реализовать? Заранее спасибо.


Ответ

Ну например, один из методов такой:
public abstract class ViewModelImpl : ViewModel where T : IModel { protected void selectData(string query) { // Логика получения reader IModel item = (T)Activator.CreateInstance(typeof(T), reader); this.Data.Add(item); } }
Ну и наследуйте конкретные классы от ViewModelImpl с нужным типом T
(Если бы конструктор T был без параметров, можно было бы обойтись без рефлексии.)

Для лучшей читаемости можно вынести метод:
private T CreateModelItem(SqlDataReader reader) { return (T)Activator.CreateInstance(typeof(T), reader); }
protected void selectData(string query) { // Логика получения reader IModel item = CreateModelItem(reader); this.Data.Add(item); }
Впрочем, у вас этот вспомогательный метод уже есть, он называется createObject

Комментариев нет:

Отправить комментарий