Экземпляр универсального класса .NET — передача переменного типа данных

Как следует из названия, я пытаюсь передать переменный тип данных в класс шаблона. Что-то вроде этого:

frmExample = New LookupForm(Of Models.MyClass) 'Works fine

Dim SelectedType As Type = InstanceOfMyClass.GetType() 'Works fine
frmExample = New LookupForm(Of SelectedType) 'Ba-bow!
frmExample = New LookupForm(Of InstanceOfMyClass.GetType()) 'Ba-bow!

LookupForm<Models.MyClass> frmExample;
Type SelectedType = InstanceOfMyClass.GetType();
frmExample = new LookupForm<SelectedType.GetType()>(); //Ba-bow
frmExample = new LookupForm<(Type)SelectedType>(); //Ba-bow

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

(Как) я могу создать экземпляр репозитория с динамическим типом во время выполнения?


person nathanchere    schedule 02.06.2010    source источник
comment
Вы не найдете никакой информации о создании динамического шаблона в VB.NET или C#, поскольку ни один из этих языков не поддерживает шаблоны. Они оба поддерживают дженерики, которые существенно различаются.   -  person John Saunders    schedule 02.06.2010
comment
возможный дубликат Pass An Instantiated System.Type как параметр типа для универсального класса   -  person usr    schedule 30.05.2014


Ответы (4)


Пример C# чего-то довольно близкого находится здесь на вопрос у меня возник:

typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });

Преобразование в VB.NET, изменение его для создания типа, а не для вызова метода, и использование имен ваших примеров для вас:

Dim frmExample as LookupForm<Models.MyClass>;
Dim SelectedType as Type = InstanceOfMyClass.GetType();   
Dim GenericLookupType as Type = GetType(LookupForm(Of)).MakeGenericType(SelectedType)
frmExample = Activator.CreateInstance(GenericLookupType, new object(){})

(А почему-то я думал, что вы хотите это в VB.NET, но вот пример C #)

LookupForm<Models.MyClass> frmExample;
Type SelectedType = InstanceOfMyClass.GetType();   
Type GenericLookupType = typeof(LookupForm<>).MakeGenericType(SelectedType);
frmExample = Activator.CreateInstance(GenericLookupType, new object[]{});
person Matt Mitchell    schedule 02.06.2010
comment
Возможно, потому, что в исходном заголовке в начале был VB.NET, а в вопросе был только пример VB.NET :) Я удалил ссылку на заголовок и добавил C #, надеясь задействовать более широкое мышление. - person nathanchere; 02.06.2010
comment
Спасибо за согласие. Вы узнаете о множестве маленьких кроличьих нор с большинством применений такого рода вещей, но это хороший способ найти граничные случаи языка. - person Matt Mitchell; 02.06.2010

Используйте Type.MakeGenericType.

Type modelType = typeof(Models.MyClass);
var repoType = typeof(LookupForm<>).MakeGenericType(new [] {modelType} );
//at this point repoType == typeof(LookupForm<Models.MyClass>);
var repo = Activator.CreateInstance(repoType );
//Ta-dah!!!

И версия VB.NET :)

    Dim modelType As Type = GetType(Models.MyClass)
    Dim repoType As Type = GetType(LookupForm(Of )).MakeGenericType(New Type() {modelType})
    'at this point repoType = GetType(LookupForm(of Models.MyClass))'
    Dim repo = Activator.CreateInstance(repoType)
    'Ta-dah!!!'
person Igor Zevaka    schedule 02.06.2010

Это звучит как кандидат на динамическую языковую среду выполнения, «динамический» тип в C #, но для этого вам потребуется использовать .NET 4.0.

person Tim Long    schedule 02.06.2010
comment
Я думаю, вам все равно придется использовать Activator.CreateInstance, но вы могли бы справиться с этим лучше во время компиляции {т.е. LookupForm‹SomeInstanceType› a = (LookupForm‹SomeInstanceType›)Activator.CreateInstance(и т. д.); } и убедитесь, что SomeInstanceType соответствует другим динамически генерируемым типам. Трудно сейчас объяснить, но вы, без сомнения, понимаете, что я имею в виду. - person Matt Mitchell; 02.06.2010

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

Type baseType = typeof(LookupForm<>);
Type selectedType = InstanceOfMyClass.GetType(); //or however else you want to get hold of it
Type genericType = baseType.MakeGenericType(new Type[] { selectedType });
object o = Activator.CreateInstance(genericType);

Конечно, теперь вы не знаете, к чему привести ваш объект (при условии, что selectedType был динамически установлен), но вы все равно можете вызывать методы для него через отражение или вы можете создать не универсальный интерфейс для его приведения и вызова методы на том.

person Alconja    schedule 02.06.2010
comment
Он не должен быть дружелюбным в реализации, пока интерфейс работает хорошо :) - person nathanchere; 02.06.2010