Как создать экземпляр класса из имени класса без использования отражения? - PullRequest
0 голосов
/ 09 февраля 2012

Есть ли способ достичь чего-то подобного?

Если "Employee" передано в качестве аргумента методу, он должен вернуть объект типа Employee.

Но без использования отражения.

Ответы [ 6 ]

2 голосов
/ 09 февраля 2012

Вы можете использовать Type.GetType (string) , чтобы получить метаданные для типа. Однако для этого требуется квалифицированное имя сборки типа, если только тип не находится в текущей выполняющейся сборке или не является частью mscorlib.dll.

Затем вы можете использовать Activator.CreateInstance (Type) для получения экземпляра.

var type = Type.GetType(typeName);
var obj = Activator.CreateInstance(type);

На данный момент статический тип obj равен System.Object. Вам нужно будет продолжать использовать отражение, чтобы получить свойства и методы, определенные для вашего фактического типа, или вы можете рассматривать объект как dynamic, предполагая, что вы не знаете во время компиляции, к какому классу следует привести результат (и если ты знал, что пропустил бы весь этот процесс).


Редактировать: с вашим добавленным ограничением нежелания использовать отражение, это меняет ваши параметры. Код будет не совсем как динамический в отношении того, что вы можете поддерживать, вам, как правило, нужно заранее обдумать идею, но это может быть хорошо, в зависимости от того, что вы пытаетесь достичь , То, что у вас может быть, это просто оператор switch или словарь, который поддерживает типы, вводя имя в виде строки.

public object GetInstanceOf(string typeName)
{
    switch (typeName)
    {
        case "Employee": return new Employee();
        case "Manager" : return new Manager();
        case "Owner" : return new Owner();
        // etc
        default: 
            throw new InvalidOperationException("typeName is not supported");
    }
}

Обратите внимание, что при таком подходе вы заранее знаете все поддерживаемые типы. Существуют и другие способы заранее узнать типы вне кода (например, конфигурация, данные), но они, как правило, вернут вас обратно в мир первой части ответа. Также обратите внимание, что ваш тип возврата по-прежнему ограничен. Это должен быть общий базовый тип или интерфейс для участвующих классов. В моем примере кода это общий базовый тип для всех классов и структур, System.Object. Для вас это может быть фабрика с базовым классом Worker или интерфейсом IWorker. Или, может быть, Employee - это основа, а ваш метод создает из нее специализированных потомков. Последние два примера дают вам доступ во время компиляции к базовым или интерфейсным методам и свойствам.

1 голос
/ 09 февраля 2012

Создание произвольного типа без отражения

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

Дженерики

В зависимости от того, что вы пытаетесь сделать, вы можете использовать очень классную технику, которая называется дженерики.Вы не можете вводить произвольное имя типа во время выполнения, так что это не обязательно отвечает на ваш вопрос полностью, но если вы знаете типы, которые вы хотите во время компиляции, это делает отличный инструмент. Это не включает никакого отражения любого вида, но это полностью время компиляции.Вот пример:

interface IParsable
{
    bool TryParse(string text);
}

class MyInt : IParsable
{
    public int Value { get; private set; }

    public static MyInt Parse(string text)
    {
        Parser parser = new Parser();
        return parser.Parse<MyInt>(text);
    }
}

class MyFloat : IParsable
{
    public float Value { get; private set; }

    public static MyFloat Parse(string text)
    {
        Parser parser = new Parser();
        return parser.Parse<MyFloat>(text);
    }
}

class Parser
{
    // The "new()" constraint means that T must have a
    // parameterless constructor.
    private T Parse<T>(string text)
        where T : IParsable, new()
    {
        // Even though T isn't actually a type, we can use
        // it as if it were, for the most part.
        T obj = new T();

        // Because we had the IParsable constraint, we can
        // use the TryParse method.
        if (!obj.TryParse(text))
        {
            throw new Exception("Text could not be parsed.");
        }

        return obj;
    }
}

Словарь Ламбдаса

Благодарю Энтони Пеграма за его гениальность (см. Комментарии ниже).Ранее у меня было это с помощью отражения, но он исправил его, чтобы он работал без каких-либо отражений, благодаря лямбда-выражениям.

static readonly IDictionary<string, Func<object>> Types = new Dictionary<string, Func<object>>()
{
    { "TypeA", () => new TypeA() },
    { "TypeB", () => new TypeB() },
    { "TypeC", () => new TypeC() },
};

// If you're okay with a bit of reflection behind-the-scenes, change "object"
// here to "dynamic", and you won't have to cast down the road.
object void GetInstance(string name)
{
    if (Types.ContainsKey(name))
    {
        return Types[name]();
    }
    else
    {
        return null;
    }
}

Предварительно созданные объекты

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

Вы можете, если хотите, каждый тип реализовать конкретный интерфейс и привести к нему вместо возврата необработанного объекта.

static readonly IDictionary<string, object> Instances = new Dictionary<string, object>()
{
    { "TypeA", new TypeA() },
    { "TypeB", new TypeB() },
    { "TypeC", new TypeC() },
};

object void GetInstance(string name)
{
    if (!Instances.ContainsKey(name))
    {
        return null;
    }

    return Instances[name];
}

Создание произвольного типа с помощью отражения

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

const string TYPE = "System.String";
Type type = Type.GetType(TYPE);
if (type == null)
{
    // Type doesn't exist--at least, not in mscorlib or current assembly,
    // or we didn't specify the assembly.
    throw new Exception("Could not find type " + TYPE + ".");
}

// Note the Type array.  These are the types of the parameters that the
// constructor takes.
ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(char), typeof(int) });
if (ctor == null)
{
    // Constructor doesn't exist that takes those parameters.
    throw new Exception("Could not find proper constructor in " + TYPE + ".");
}

// Note the object array.  These are the actual parameters passed to the
// constructor.  They should obviously match the types specified above.
string result = (string)ctor.Invoke(new object[] { 'a', 5 });
1 голос
/ 09 февраля 2012

Да, чем вы можете сделать с помощью " Отражение "

Попробуйте

Employee employee =(Employee)Activator.CreateInstance("Employee"); 

проверить @ jon skeet ответ: Как мне создать экземпляр из строки в C #?

0 голосов
/ 09 февраля 2012

Используя отражение , вы можете найти типы в сборках, будь то исполняющая сборка или другие загруженные (вы можете загрузить их по запросу). Без указания полного примера того, как это может работать в вашем сценарии, вы затем использовали бы что-то вроде Activator.CreateInstance для создания экземпляров найденных объектов.

0 голосов
/ 09 февраля 2012

Используя отражение, так как @vulkanino говорит, что в итоге вы получите что-то вроде этого:

Employee instance = (Employee)Activator.CreateInstance("MyNamespace.Employee, MyAssembly");

Надеюсь, это поможет вам.

0 голосов
/ 09 февраля 2012

Вы можете использовать Activator.CreateInstance()

Employee employee =(Employee)Activator.CreateInstance("Namespace", "Employee");
...