Создать экземпляр с активатором

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

class Class1{ }
class Class2{ }
class Class3{ }

и у меня есть переменная типа

Type t = /*some type unknown at compile-time*/;

переменная t относится к классу 1, классу 2 или классу 3. Я хочу создать экземпляр этого класса. Насколько я знаю, я могу использовать следующее утверждение:

object instance = Activator.CreateInstance(t);

Но я получаю объект. И вопрос: как мне привести этот объект к типу, который находится в переменной t. Или, может быть, кто-то может предложить обходной путь. Спасибо


person steavy    schedule 13.10.2012    source источник


Ответы (4)


Если нет какого-то общего базового класса или интерфейса, который разделяют все 3, вы не можете - все, что вы можете назвать, это «объект». Подумайте о том, чтобы все они реализовали интерфейс и привели к нему.

person Marc Gravell    schedule 13.10.2012

Если вы хотите избежать отражения, то

public interface IClass { }
class Class1 : IClass { }
class Class2 : IClass { }
class Class3 : IClass { }

IClass instance = (IClass)Activator.CreateInstance(t);
person L.B    schedule 13.10.2012

Вы можете использовать ключевое слово dynamic:

dynamic instance = Activator.CreateInstance(t);

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

Дополнительные сведения см. здесь.

person Omar    schedule 13.10.2012

Вам сказали, что вы не можете, и тем не менее вы можете.

Сначала давайте посмотрим ваш код:

class Class1{ }
class Class2{ }
class Class3{ }

void Main()
{
    Type t = /*some type unknown at compile-time*/;
    object instance = Activator.CreateInstance(t);
}

И ваш вопрос:

как привести этот объект к типу, который находится в переменной t.

Ну, если я только смотрю на эту информацию, то ответ такой: нельзя, потому что существует бесконечное множество типов, которые могут быть в переменной t, на самом деле, некоторые из них могли быть определены уже после написания этого кода. (их еще не было).

Ну, вроде бы, есть и другая информация:

переменная t относится к классу 1, классу 2 или классу 3.

Это означает, что у вас есть конечный набор возможных типов, которые могут быть в переменной t.

Имея это в виду, вы можете просто проверить их, например:

class Class1{ }
class Class2{ }
class Class3{ }

void Main()
{
    var possibleTypes = new Type[]
    {
        typeof(Class1),
        typeof(Class2),
        typeof(Class3)
    };
    Type t = possibleTypes[(new Random()).Next(possibleTypes.Length)];
    object instance = Activator.CreateInstance(t);
    if (t.Equals(typeof(Class1)))
    {
        DoSomethingWithClass1(instance as Class1);
    }
    else if (t.Equals(typeof(Class2)))
    {
        DoSomethingWithClass2(instance as Class2);
    }
    else if (t.Equals(typeof(Class3)))
    {
        DoSomethingWithClass3(instance as Class3);
    }
}

void DoSomethingWithClass1(Class1 instance)
{
    //...
}

void DoSomethingWithClass2(Class2 instance)
{
    //...
}

void DoSomethingWithClass3(Class3 instance)
{
    //...
}

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

«Это не очень универсально», — скажете вы, — «я не хочу писать новый метод каждый раз, когда появляется новый класс!». И я согласен, вы могли бы решить это, зайдя в отделы Reflection. Но, честно говоря, это бессмысленно. Как вам уже сказали, в этих классах нет ничего общего, поэтому вам лучше создать интерфейс, чтобы избежать отражения .

Кроме того, что вы хотели сделать с этим объектом? Скорее всего, вы сможете найти методы, общие для всех классов, и использовать те из них в своем новом интерфейсе, которые с этого момента будут реализовываться соответствующим классом.

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

person Theraot    schedule 14.10.2012
comment
спасибо за ответ. Действительно, у меня много классифицированных (30-50), поэтому написание случаев переключения не является хорошей идеей для меня на данный момент. Решение найдено путем создания общего базового класса. - person steavy; 14.10.2012