2013-07-08 2 views
19

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

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(); 

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

ответ

20

Что вы имеете в виду этой части является возможно:

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

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

Что вы имеете в виду этой части не:

AnimalContext<a.GetType()> a_Context 

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

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

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. Но опять же, имейте в виду, у вас есть нет преимуществ общих типов при этом.

+3

Все, кто ответил, дали ответ, который предоставил немного больше информации, чем предыдущий ответ. Все были верны и превосходны по качеству, но только один может быть выбран как «Ответ», поэтому я выбрал именно тот, который был наиболее наглядным. Я хотел бы поблагодарить всех, кто ответил, и я ценю всю помощь (особенно поздно вечером в воскресенье). –

+0

Что делать, если мой класс не является общим, но внутри метода является то, как я буду использовать MakeGenericType в этом случае –

6

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

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

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

a_Context.DoAnimalStuff(); 

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

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

Вам необходимо будет создать тип usin g Отразить, а затем вызвать этот тип. Что-то вроде:

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

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

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

Смежные вопросы