Подтвердить что ты не робот

Инициализация общей переменной из переменной типа С#

У меня есть класс, который принимает тип Generic как часть его инициализации.

public class AnimalContext<T>
{
    public DoAnimalStuff()
    {
        //AnimalType Specific Code
    }
}

Теперь я могу сделать

AnimalContext<Donkey> donkeyContext = new AnimalContext<Donkey>();
AnimalContext<Orca> orcaContext = new AnimalContext<Orca>();

Но то, что мне нужно/нужно сделать, - это объявить AnimalContext, инициализированный типом, который известен только во время выполнения. Например,

Animal a = MyFavoriteAnimal(); //returns an instance of a class 
                               //implementing an animal
AnimalContext<a.GetType()> a_Context = new AnimalContext<a.GetType()>();
a_Context.DoAnimalStuff();

Возможно ли это? Кажется, я не могу найти ответ для этого онлайн.

4b9b3361

Ответ 1

Что вы подразумеваете под этой частью, возможно:

new AnimalContext<a.GetType()>();

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

Что вы подразумеваете под этой частью:

AnimalContext<a.GetType()> a_Context

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

Теперь, чтобы создать экземпляр родового типа во время выполнения, когда вы не знаете тип до выполнения, вы можете сказать:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);   

Обратите внимание, что тип времени компиляции a_context равен object. Вам нужно будет указать a_context тип или интерфейс, который определяет методы, необходимые для доступа. Часто то, что вы увидите здесь, означает, что общий тип AnimalContext<T> реализует какой-либо интерфейс (скажем IAnimalContext) или наследуется от не общего базового класса (скажем AnimalContext), который определяет методы, которые им нужны (так что тогда вы можете использовать a_context для интерфейса или для не общего базового класса). Другой альтернативой является использование dynamic. Но опять же, имейте в виду, что у вас нет преимуществ от общих типов при этом.

Ответ 2

Вы можете использовать отражение с общим типом с помощью метода MakeGenericType и воспользоваться преимуществом ключевого слова dynamic:

var type = typeof (AnimalContext<>).MakeGenericType(a.GetType());
dynamic a_Context = Activator.CreateInstance(type);

Итак, вы можете позвонить:

a_Context.DoAnimalStuff();

Или снова использовать отражение метода вызова:

type.GetMethod("DoAnimalStuff").Invoke(a_Context, null);

Ответ 3

Вам нужно будет создать тип с помощью Reflection, а затем вызвать этот тип. Что-то вроде:

Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());

dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();

Использование динамических означает, что переменная контекста будет оцениваться во время выполнения, позволяя вам вызвать метод DoAnimalStuff.