Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
57 / 57 / 20
Регистрация: 04.07.2013
Сообщений: 524
1

Type.MakeGenericType

11.09.2015, 00:54. Показов 2721. Ответов 10

Author24 — интернет-сервис помощи студентам
Доброго времени суток. Если можете, поясните пожалуйста на пальцах как работает этот метод. Читал несколько туториалов - пока трудновато въехать. Спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.09.2015, 00:54
Ответы с готовыми решениями:

Реализовать метод string[] Method(Type type), который будет выводить все члены, видимые вне сборки, помеченные атрибута
Пожалуйста, помогите. Реализовать метод string Method(Type type), который будет выводить все...

Ошибка: The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
Помогите решить ошибку Если в календаре выбираю дату больше 13 выдаёт ошибку The conversion of a...

Оператор "*" не может применяться к операндам типа "type" и "type"
public vector module() { return new vector(x * x + y * y + z * z); } ...

Десериализация XML с xsi:type
Всем доброго времени суток. Не получается десериализовать xml такого вида: <ns11:root...

10
Заблокирован
11.09.2015, 01:06 2
Цитата Сообщение от KrekerOK Посмотреть сообщение
этот метод.
и где этот метод? тут все натыкано уже
0
Администратор
Эксперт .NET
17019 / 13372 / 5217
Регистрация: 17.03.2014
Сообщений: 27,342
Записей в блоге: 1
11.09.2015, 07:45 3
KrekerOK, с помощью MakeGenericType можно подставить недостающие тип-аргументы в обобщенный тип чтобы он стал конкретным обобщенным типом чтобы его можно было сконструировать.
C#
1
2
3
4
5
6
7
8
Type genericWithoutTypeArguments = typeof(Dictionary<,>);
// Если убрать комментарий, то мы получим исключение т.к. у типа нет тип-аргументов
// ArgumentException: Cannot create an instance of System.Collections.Generic.Dictionary`2[TKey,TValue] because Type.ContainsGenericParameters is true.
// object dict1 = Activator.CreateInstance(genericWithoutTypeArguments);
 
Type genericWithTypeArguments = genericWithoutTypeArguments.MakeGenericType(typeof(string), typeof(int));
// Успешно создаем Dictionary<string,int>
Dictionary<string,int> dict2 = (Dictionary<string,int>)Activator.CreateInstance(genericWithTypeArguments);
0
Эксперт .NET
10566 / 6490 / 1506
Регистрация: 25.05.2015
Сообщений: 19,658
Записей в блоге: 14
11.09.2015, 08:30 4
Создание контрола с <T>
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void ShowList(Type type)
        {
            Type generic = typeof(ControlVocabularyList<>);
            Type[] typeArgs = { type };
            Type constructed = generic.MakeGenericType(typeArgs);
 
            object o = Activator.CreateInstance(constructed, new object[] { this.mApp });
            Control control = o as Control;
 
            if (control != null)
            {
                this.mApp.Controls.Show(control);
            }
        }
0
57 / 57 / 20
Регистрация: 04.07.2013
Сообщений: 524
11.09.2015, 10:03  [ТС] 5
Спасибо, становится немного ясней, но пока на практике не могу использовать. Например есть такой код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SomeModel<T>
{
    public int FirstProperty { get; set; }
    public string SecondProperty{ get; set; }
    public void MeMethod <T> (T someArgument)
    {
        //implementation
    }
}
 
class TargetModel
{
    public int someProperty_1{ get; set; }
    public int someProperty_1{ get; set; }
}
Хочу создать объект SomeModel <TargetModel>.

Рефлексией получаю тип TargetModel. Далее:
C#
1
2
3
Type type= typeof(SomeModel<>);
                Type typeForCreateInstance = type.MakeGenericType(typeObtainedByReflection);
                var myObject = Activator.CreateInstance(typeForCreateInstance );
В результате я получаю объект SomeModel <TargetModel>, но в этом объекте доступны только свойства, метод не доступен. Что я делаю не верно? Спасибо.

Добавлено через 4 минуты
Если сделать приведение типов
C#
1
(SomeModel<TargetModel>)myObject
тогда и метод становится видимым.

Можно ли добиться того же эффекта не указывая явное приведение типов?

Добавлено через 6 минут
Без приведения типов и свойства недоступны (они просто показывались в дебагере). То есть получается, что Activaor возвращает object.
0
Администратор
Эксперт .NET
17019 / 13372 / 5217
Регистрация: 17.03.2014
Сообщений: 27,342
Записей в блоге: 1
11.09.2015, 10:07 6
Цитата Сообщение от KrekerOK Посмотреть сообщение
C#
1
var myObject = Activator.CreateInstance(typeForCreateInstance );
но в этом объекте доступны только свойства, метод не доступен
Ты что-то путаешь. Переменная myObject имеет тип object и соответственно на ней будут доступны только члены System.Object.

Цитата Сообщение от KrekerOK Посмотреть сообщение
Можно ли добиться того же эффекта не указывая явное приведение типов?
Можно с помощью рефлексии, но это будет некрасиво. Плюс ты зачем-то добавил тип аргумент у MeMethod что означает что для него нужно будет вызвать MakeGenericMethod.
C#
1
2
3
4
var myObject = Activator.CreateInstance(typeForCreateInstance);
typeForCreateInstance.GetMethod("MeMethod")
    .MakeGenericMethod(typeof(string))
    .Invoke(myObject, new object[] { "Hello" });
Добавлено через 3 минуты
Цитата Сообщение от KrekerOK Посмотреть сообщение
Без приведения типов и свойства недоступны (они просто показывались в дебагере).
Отладчик и среда исполнения всегда знают настоящий тип значения.

Цитата Сообщение от KrekerOK Посмотреть сообщение
То есть получается, что Activaor возвращает object.
Разумеется. Для этого достаточно посмотреть справку или подсказку IntelliSense.
0
57 / 57 / 20
Регистрация: 04.07.2013
Сообщений: 524
11.09.2015, 10:22  [ТС] 7
Да, я уже понял что путаю. Дело в том, что я смотрел в дебагере, а там свойства как бы видимые, но в реальности их они не доступны. По идеи метод может быть и обычным. А как сделать приведение с помощью рефлексии?
0
Администратор
Эксперт .NET
17019 / 13372 / 5217
Регистрация: 17.03.2014
Сообщений: 27,342
Записей в блоге: 1
11.09.2015, 10:30 8
KrekerOK, "динамическое" приведение здесь не поможет т.к. для обращения к членам SomeModel<T> тебе нужно иметь переменную этого типа на этапе компиляции. Или оставить переменную типа object и обращаться к нужным членам с помощью рефлексии уже на этапе выполнения.

Что именно ты пытаешься сделать? Зачем конструировать SomeModel<T> с помощью рефлексии?
0
57 / 57 / 20
Регистрация: 04.07.2013
Сообщений: 524
11.09.2015, 10:56  [ТС] 9
Опишу ситуацию вкратце. Есть базовый интерфейс IMyBaseInterface. Его реализуют несколько классов (5,10,15...не важно). Есть хранилище в котором хранятся имена этих классов (можно вручную забивать, можно каждый раз обновлять с помощью рефлексии). В программу поступает строка - название класса, задача программы состоит в том чтобы создать экземпляр этого класса. Для этого я решил завести словарик (тип значения - делегат типа базового интерфейса) в который при старте программы я собираю все классы с их методами которые возвращают экземпляр класса (CreateInstance). CreateInstance возвращает IMyBaseInterface. В интерфейсе IMyBaseInterface есть метод ExecuteOperation ,на данном этапе он представляет собою switch который какой void метод выполнить (список метод также есть в хранилище). В будущем также планирую переделать на рефлексию.
Для того чтобы заполнить мой словарик - я почему то начал рыть в сторону Generic, но оказалось не то (хотя может быть и с помощью Generic также можно это реализовать). Оказалось всё немного проще:
C#
1
2
3
4
5
6
7
8
9
10
11
12
class TestObjectModel
    {
        public delegate IBaseTestObject CreateMethod();
        public TestObjects EnumTestObject { get; set; }
        public CreateMethod DefaultConstructor { get; set; }
 
 
        public TestObjectModel(Type obj, object myObject)
        {
            DefaultConstructor = (CreateMethod)Delegate.CreateDelegate(typeof(CreateMethod), myObject, obj.GetMethod("SpecialMethod"), true);
        }
    }
Теперь во время старта программы я делаю примерно так:
C#
1
2
3
4
5
6
7
8
9
var baseInterfaceType = typeof(IBaseTestObject);
                var objectsThatImplementBaseInterface = AppDomain.CurrentDomain.GetAssemblies().SelectMany(asem => asem.GetTypes())
                                                                 .Where(x => baseInterfaceType.IsAssignableFrom(x) && x.IsClass).ToList();
                foreach(var obj in objectsThatImplementBaseInterface)
                {
                    var myObject = Activator.CreateInstance(obj);
                    TestObjectModel tom = new TestObjectModel(obj, myObject);
                 }
//....
Добавлено через 2 минуты
Ну и в каждом классе которые реализует IBaseTestInterface есть соответственный метод:
C#
1
2
3
4
5
6
7
class Address_Test: IBaseTestObject
{ 
    public IBaseTestObject SpecialMethod()
    {
        return new Address_Test();
    } 
}
Добавлено через 7 минут
Цель всех этих лишних телодвижений - улучшить масштабируемость системы и убрать из программы switch типа
C#
1
2
3
4
5
6
7
8
9
10
public IBaseTestObject GetObject(string objectName)
{
switch(objectName)
{
case "Address": return new Address_Test)();
case "": return new ...
//...
default: return null;
}
}
Т. к. в принципе производительность не стоит на первом месте, то я думаю что это вполне адекватное решение проблемы.
0
Администратор
Эксперт .NET
17019 / 13372 / 5217
Регистрация: 17.03.2014
Сообщений: 27,342
Записей в блоге: 1
11.09.2015, 11:05 10
KrekerOK, ты немного перемудрил. Раз все типы реализуют общий интерфейс, то приводи то что вернул Activator.CreateInstance к IBaseTestObject и вызывай метод SpecialMethod.
0
57 / 57 / 20
Регистрация: 04.07.2013
Сообщений: 524
11.09.2015, 11:11  [ТС] 11
Ну по сути я так и делаю, просто вместо того чтобы каждый раз узнавать рефлексией объект, я создаю словарь с методами всех объектов, и определю ещё один метод который будет принимать строку, делать поиск по словарю и выполнять соответствующий метод для создания объекта.

Добавлено через 2 минуты
Что то вроде этого:

C#
1
2
3
4
public IBaseTestObject CreateNewInstance(string testObjectName)
        {
            return TestObjectModels[testObjectName].DefaultConstructor.Invoke();
}
0
11.09.2015, 11:11
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.09.2015, 11:11
Помогаю со студенческими работами здесь

Type.GetType вместо typeof()
Приветствую. Получаю System.Type через typeof(NameClass). Но необходимо получать тип по...

Нужно из Type получить class
public void TryTest(string className) //Допустим className = &quot;RequestData&quot; { ...

Cannot implicitly convert type 'object' to 'string'
Здравствуйте, подскажите пожалуйста как быть! Хочу посредством WMI занести например имя компа и ОС...

Получить Type компонента по его имени
вобщем химичу я со стандартными компонентами, пытаюсь получить Type, ну к примеру кнопки, и не...

Инициализация generic классов используя System.Type
Здравствуйте. Есть метод который возвращает через делегат имена свойств объекта и ссылку на сами...

Type or namespace definition, or end-of-file expected
Привет. Подскажите пожалуйста забыл как решается такая ошибка: Type or namespace definition, or...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru