Передайте Instantiated System.Type как параметр типа для универсального класса - PullRequest
167 голосов
/ 05 ноября 2008

Название неясное. Я хочу знать, возможно ли это:

string typeName = <read type name from somwhere>;
Type myType = Type.GetType(typeName);

MyGenericClass<myType> myGenericClass = new MyGenericClass<myType>();

Очевидно, MyGenericClass описывается как:

public class MyGenericClass<T>

Сейчас компилятор жалуется, что «Тип или пространство имен« myType »не может быть найдено.

Ответы [ 5 ]

204 голосов
/ 05 ноября 2008

Вы не можете сделать это без отражения. Тем не менее, вы можете сделать это с отражением. Вот полный пример:

using System;
using System.Reflection;

public class Generic<T>
{
    public Generic()
    {
        Console.WriteLine("T={0}", typeof(T));
    }
}

class Test
{
    static void Main()
    {
        string typeName = "System.String";
        Type typeArgument = Type.GetType(typeName);

        Type genericClass = typeof(Generic<>);
        // MakeGenericType is badly named
        Type constructedClass = genericClass.MakeGenericType(typeArgument);

        object created = Activator.CreateInstance(constructedClass);
    }
}

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

Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);
14 голосов
/ 05 ноября 2008

К сожалению нет там нет. Универсальные аргументы должны быть разрешены во время компиляции как 1) допустимый тип или 2) другой универсальный параметр. Невозможно создать универсальные экземпляры на основе значений времени выполнения без большого труда использовать отражение.

2 голосов
/ 13 июня 2015

Мои требования немного отличались, но, надеюсь, кому-то помогут. Мне нужно было прочитать тип из конфига и создать экземпляр универсального типа динамически.

namespace GenericTest
{
    public class Item
    {
    }
}

namespace GenericTest
{
    public class GenericClass<T>
    {
    }
}

Наконец, вот как вы это называете. Определить тип с помощью обратного кавычка .

var t = Type.GetType("GenericTest.GenericClass`1[[GenericTest.Item, GenericTest]], GenericTest");
var a = Activator.CreateInstance(t);
2 голосов
/ 14 октября 2014

Некоторые дополнительные, как работать с кодом ножниц. Предположим, у вас есть класс, похожий на

public class Encoder() {
public void Markdown(IEnumerable<FooContent> contents) { do magic }
public void Markdown(IEnumerable<BarContent> contents) { do magic2 }
}

Предположим, во время выполнения у вас есть FooContent

Если бы вы смогли связать во время компиляции, вы бы хотели

var fooContents = new List<FooContent>(fooContent)
new Encoder().Markdown(fooContents)

Однако вы не можете сделать это во время выполнения. Чтобы сделать это во время выполнения, вы должны сделать следующее:

var listType = typeof(List<>).MakeGenericType(myType);
var dynamicList = Activator.CreateInstance(listType);
((IList)dynamicList).Add(fooContent);

Для динамического вызова Markdown(IEnumerable<FooContent> contents)

new Encoder().Markdown( (dynamic) dynamicList)

Обратите внимание на использование dynamic в вызове метода. Во время выполнения dynamicList будет List<FooContent> (дополнительно также равным IEnumerable<FooContent>), поскольку даже использование динамического языка все еще основано на строго типизированном языке, средство связывания времени выполнения выберет соответствующий метод Markdown. Если нет точных совпадений типов, он будет искать метод параметра объекта, и если ни один из них не будет совпадать, будет сгенерировано исключение связывателя времени выполнения, предупреждающее, что ни один метод не соответствует.

Очевидным недостатком этого подхода является огромная потеря безопасности типов во время компиляции. Тем не менее, код в этом направлении позволит вам работать в очень динамичном смысле, который во время выполнения все еще полностью набирается, как вы ожидаете.

0 голосов
/ 28 декабря 2018

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

public class Type1 { }

public class Type2 { }

public class Generic<T> { }

public class Program
{
    public static void Main()
    {
        var typeName = nameof(Type1);

        switch (typeName)
        {
            case nameof(Type1):
                var type1 = new Generic<Type1>();
                // do something
                break;
            case nameof(Type2):
                var type2 = new Generic<Type2>();
                // do something
                break;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...