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

С#: создание экземпляров классов из XML

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

<class1 prop1="foo" prop2="bar"/>

и превращая это в:

blah = new class1();
blah.prop1="foo";
blah.prop2="bar";

В общем случае. То, что я не знаю, как это сделать, это взять строку prop1 в файле конфигурации и превратить ее в фактический аксессуар свойства в коде. Есть ли в С# объекты метапрограммирования, чтобы это разрешить?

4b9b3361

Ответ 1

Может быть проще сериализовать классы в/из xml, вы можете просто передать XmlReader (который читает ваш файл конфигурации) в десериализатор, и он сделает все остальное для вас.

Это довольно хорошая статья о сериализации

Изменить

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

Сериализация в XML не нуждается в этом, и вы все еще можете иметь безопасность типов, гарантируя, что вы пишете полное имя типа в XML файл, поэтому тот же тип автоматически загружается.

Ответ 2

Отражение позволяет это сделать. Вы также можете посмотреть Сериализация XML.

Type type = blah.GetType();
PropertyInfo prop = type.GetProperty("prop1");
prop.SetValue(blah, "foo", null);

Ответ 3

Я бы также предложил сериализацию Xml, как уже упоминалось ранее. Вот образец, который я собрал, чтобы продемонстрировать. Атрибуты используются для подключения имен из Xml к фактическим именам и типам свойств в структуре данных. Атрибуты также перечисляют все допустимые типы, которые могут войти в коллекцию Things. Все в этой коллекции должно иметь общий базовый класс. Вы сказали, что у вас уже есть общий интерфейс, но вам, возможно, придется изменить его на абстрактный базовый класс, потому что этот образец кода не сразу работал, когда Thing был интерфейсом.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            string xml =
                "<?xml version=\"1.0\"?>" + 
                "<config>" +
                "<stuff>" + 
                "  <class1 prop1=\"foo\" prop2=\"bar\"></class1>" +
                "  <class2 prop1=\"FOO\" prop2=\"BAR\" prop3=\"42\"></class2>" +
                "</stuff>" +
                "</config>";
            StringReader sr = new StringReader(xml);
            XmlSerializer xs = new XmlSerializer(typeof(ThingCollection));
            ThingCollection tc = (ThingCollection)xs.Deserialize(sr);

            foreach (Thing t in tc.Things)
            {
                Console.WriteLine(t.ToString());
            }
        }
    }

    public abstract class Thing
    {
    }

    [XmlType(TypeName="class1")]
    public class SomeThing : Thing
    {
        private string pn1;
        private string pn2;

        public SomeThing()
        {
        }

        [XmlAttribute("prop1")]
        public string PropertyNumber1
        {
            get { return pn1; }
            set { pn1 = value; }
        }

        [XmlAttribute("prop2")]
        public string AnotherProperty
        {
            get { return pn2; }
            set { pn2 = value; }
        }
    }

    [XmlType(TypeName="class2")]
    public class SomeThingElse : SomeThing
    {
        private int answer;

        public SomeThingElse()
        {
        }

        [XmlAttribute("prop3")]
        public int TheAnswer
        {
            get { return answer; }
            set { answer =value; }
        }
    }

    [XmlType(TypeName = "config")]
    public class ThingCollection
    {
        private List<Thing> things;

        public ThingCollection()
        {
            Things = new List<Thing>();
        }

        [XmlArray("stuff")]
        [XmlArrayItem(typeof(SomeThing))]
        [XmlArrayItem(typeof(SomeThingElse))]
        public List<Thing> Things
        {
            get { return things; }
            set { things = value; }
        }
    }
}

Ответ 4

Отражение или XML-сериализация - это то, что вы ищете.

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

public IYourInterface GetClass(string className)
{
    foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) 
    {            
        foreach (Type type in asm.GetTypes())
        {
            if (type.Name == className)
                return Activator.CreateInstance(type) as IYourInterface;
        }   
    }

    return null;
}

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

Для присвоения значений свойств вы также используете отражение. Что-то вдоль линий

IYourInterface o = GetClass("class1");
o.GetType().GetProperty("prop1").SetValue(o, "foo", null);

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

Ответ 5

Множество средств метапрограммирования.

В частности, вы можете получить ссылку на сборку, которая содержит эти классы, а затем легко получить Type класса от его имени. См. Assembly.GetType Method (String).

Оттуда вы можете создать экземпляр класса с помощью Activator или конструктора самого Type. См. Activator.CreateInstance Method.

Как только у вас есть экземпляр, вы можете снова установить свойства, используя объект Type. См. Метод Type.GetProperty и/или Метод Type.GetField вдоль Свойство PropertyInfo.SetValue.

Ответ 7

Я думаю, вы можете использовать Dynamics здесь. Создайте ExpandoObject, его можно использовать либо как Словарь для задания свойств из xml config.

Ответ 8

Отражение - это то, что вы хотите. Reflection + TypeConverter. У вас не так много времени, чтобы объяснить, а просто Google, и вам должно быть хорошо на вашем пути. Или вы можете просто использовать XML-сериализатор, но тогда вы должны придерживаться формата, но отлично работает.