Страницы

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

воскресенье, 1 марта 2020 г.

C# Создание экземпляра потомка по типу, определенному в базовом классе

#c_sharp #ооп


Есть базовый класс

public abstract class Session
{
    public abstract SessionType SessionType { get; }
}


И есть куча его наследников, возвращающих нужный тип SessionType.

Каждому типу строго соответствует один наследник.

Вопрос:

Как создать экземпляр нужного потомка зная тип.

ПС.
Понятно, что можно сделать метод по свичу создающий потомков. 
Но тогда при каждом создании нового типа нужно будет добавлять новую инициализацию
объекта.
Можно ли это сделать более простым способом?
    


Ответы

Ответ 1



Как вариант можно сделать свой атрибут, через который вы будете устанавливать соответствие типов между Session и SessionType: [AttributeUsage(AttributeTargets.Class)] public class SessionAttribute : Attribute { public SessionAttribute(Type type) { Type = type; } public Type Type { get; } } Декорируем нашим атрибутом SessionType: public class FirstSession : Session { public override SessionType SessionType => new FirstSessionType(); } public class SecondSession : Session { public override SessionType SessionType => new SecondSessionType(); } [Session(typeof(FirstSession))] public class FirstSessionType : SessionType { } [Session(typeof(SecondSession))] public class SecondSessionType : SessionType { } После этого можно создать экземпляр Session зная SessionType: public static Session CreateInstanceOfSession(Type sessionType) { var attr = sessionType.GetCustomAttribute(typeof(SessionAttribute)) as SessionAttribute; if (attr != null) { return (Session)Activator.CreateInstance(attr.Type); } return null; } Проверяем: Console.WriteLine(CreateInstanceOfSession(typeof(FirstSessionType)).ToString()); //Выведет FirstSession Console.WriteLine(CreateInstanceOfSession(typeof(SecondSessionType)).ToString()); //Выведет SecondSession

Ответ 2



Большое спасибо за ответы. Оба ответа мне помогли. Решил задачу немного другим способом, отличным от обоих предложенных. Точнее, соединил их в одно решение. Идея: Для каждого класса-потомка устанавливается атрибут. Потом сканируем потомков и определяем по атрибуту нужный тип Создаем экземпляр. Реализация: using System; using System.Linq; using System.Reflection; namespace TestAttrib { public enum SessionType { One , Two } public abstract class Session { public abstract SessionType SessionType { get; } public static Session construct(SessionType sessionType) { Type typeSession = typeof(Session); Type type = Assembly.GetAssembly(typeSession).GetTypes().SingleOrDefault(t => t.IsSubclassOf(typeSession) && (t.GetCustomAttribute(typeof(SessionTypeAttribute)) as SessionTypeAttribute).SessionType == sessionType ); if (type != null) { return (Session)Activator.CreateInstance(type); } return null; } } [SessionType(SessionType.One)] public class Session_One : Session { public override SessionType SessionType => SessionType.One; } [SessionType(SessionType.Two)] public class Session_Two : Session { public override SessionType SessionType => SessionType.Two; } [AttributeUsage(AttributeTargets.Class)] public class SessionTypeAttribute : Attribute { public SessionTypeAttribute(SessionType sessionType) { SessionType = sessionType; } public SessionType SessionType { get; } } class Program { static void Main(string[] args) { Console.WriteLine(Session.construct(SessionType.One).ToString()); //Выведет TestAttrib.Session_One Console.WriteLine(Session.construct(SessionType.Two).ToString()); //Выведет TestAttrib.Session_Two Console.ReadLine(); } } }

Ответ 3



Нет, "более простым" способом это сделать нельзя. Но можно сделать более сложным. Вы можете просканировать все ассембли процесса и собрать все типы, которые являются неабстрактными потомками Session. Потом создав инстанс каждого из этих типов и вызвав у него SessionType, заполните лукап таблицу для нахождения типа потомка Session по значению SessionType.

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

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