Динамически создавать объект ‹Тип›

В моей базе данных есть таблица, которую я использую для управления отношениями в своем приложении. это довольно просто по своей природе - parentType, parentId, childType, childId... все как целые числа. Я делал эту настройку раньше, но я сделал это с настройкой переключателя/кейса, когда у меня было 6 разных таблиц, которые я пытался связать. Теперь у меня есть 30 таблиц, с которыми я пытаюсь это сделать, и я хотел бы иметь возможность сделать это без необходимости писать 30 записей case в моей команде переключения.

Есть ли способ, которым я могу ссылаться на класс .Net, используя строку? Я знаю, что это неверно (потому что я пробовал несколько вариантов этого):

Type t = Type.GetType("WebCore.Models.Page");
object page = new t();

Я знаю, как получить тип объекта, но как мне использовать его на лету для создания нового объекта?


person thaBadDawg    schedule 23.02.2009    source источник


Ответы (6)


Эта ссылка должна помочь:
https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

Activator.CreateInstance создаст экземпляр указанного типа.

Вы можете обернуть это в общий метод следующим образом:

public T GetInstance<T>(string type)
{
    return (T)Activator.CreateInstance(Type.GetType(type));
}
person Jason Miesionczek    schedule 23.02.2009
comment
Это не сработает, если сборка, содержащая тип, еще не загружена в AppDomain. - person Andrew Hare; 23.02.2009
comment
Кроме того, чтобы вызвать этот метод, OP должен иметь доступ к типу во время компиляции - исходный вопрос задавался тем, как создать экземпляр во время выполнения из строки. - person Andrew Hare; 23.02.2009
comment
я просто основываю свой ответ на примере, приведенном в вопросе. - person Jason Miesionczek; 23.02.2009
comment
Ах, вы правы - похоже, у OP есть доступ к типу! Моя ошибка - (-1) удалено! - person Andrew Hare; 23.02.2009
comment
Ваш пример также потребует знания типа во время компиляции :) - person Jason Miesionczek; 23.02.2009
comment
Я получаю эту ошибку: Аргументы типа для метода «GetInstance‹T›(строка)» не могут быть выведены из использования. Попробуйте явно указать аргументы типа. Если я указываю аргументы типа, это как бы противоречит цели этого. - person Tod; 19.10.2017
comment
Один из возможных вариантов использования этой функции — если у вас есть иерархия объектов с интерфейсом в качестве корня. Вы можете указать интерфейс как явный тип, а затем передать конкретный класс, реализующий этот интерфейс, в качестве параметра функции. - person Jason Miesionczek; 23.10.2017

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

Выполнение этого таким образом безопасно для типов и не требует отражения.

T CreateType<T>() where T : new()
{
   return new T();
}
person Judah Gabriel Himango    schedule 23.02.2009
comment
Он не требует отражения на уровне исходного кода — однако он использует Activator.CreateInstance в сгенерированном IL. - person Jon Skeet; 23.02.2009
comment
отражение требуется, потому что OP указан с использованием строки для идентификации типа. - person Jason Miesionczek; 23.02.2009

public static T GetInstance<T>(params object[] args)
{
     return (T)Activator.CreateInstance(typeof(T), args);
}

Я бы использовал Activator.CreateInstance() вместо кастинга, так как Activator имеет конструктор для дженериков.

person AmuuuInjured    schedule 04.06.2011

Вы хотите использовать Activator.CreateInstance.

Вот пример того, как это работает:

using System;
using System.Runtime.Remoting;

class Program
{
    static void Main()
    {
        ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32");

        Int32 i = (Int32)o.Unwrap();
    }
}
person Andrew Hare    schedule 23.02.2009

Предполагая, что у вас есть следующий тип:

public class Counter<T>
{
  public T Value { get; set; }
}

и иметь квалифицированное имя сборки типа, вы можете построить его следующим образом:

string typeName = typeof(Counter<>).AssemblyQualifiedName;
Type t = Type.GetType(typeName);

Counter<int> counter = 
  (Counter<int>)Activator.CreateInstance(
    t.MakeGenericType(typeof(int)));

counter.Value++;
Console.WriteLine(counter.Value);
person sduplooy    schedule 23.02.2009

Вот функция, которую я написал, которая клонирует запись типа T, используя отражение. Это очень простая реализация, я не занимался сложными типами и т.д.

 public static T Clone<T>(T original)
    {
        T newObject = (T)Activator.CreateInstance(original.GetType());

        foreach (var prop in original.GetType().GetProperties())
        {
            prop.SetValue(newObject, prop.GetValue(original));
        }

        return newObject;
    }

Я надеюсь, что это может помочь кому-то.

Асаф

person Assaf S.    schedule 19.01.2017