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

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

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

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

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

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

13
задан 20.08.2017, 03:57

7 ответов

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

Type type = blah.GetType();
PropertyInfo prop = type.GetProperty("prop1");
prop.SetValue(blah, "foo", null);
9
ответ дан 01.10.2019, 15:20

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

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

Редактирование

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

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

9
ответ дан 01.10.2019, 15:20

Я также предложил бы 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; }
        }
    }
}
8
ответ дан 01.10.2019, 15:20

Отражательная или сериализация 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 для пропуска выполнения тяжелого подъема себя.

6
ответ дан 01.10.2019, 15:20

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

Абстрактный Шаблон разработки

Фабрики
1
ответ дан 01.10.2019, 15:20

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

А именно, можно получить ссылку на блок, который содержит эти классы, тогда легко доберитесь Type из класса с его имени. См. блок. Метод GetType (Строка) .

Оттуда, можно инстанцировать класса с помощью Activator или конструктор Type самого. См. Активатор. Метод CreateInstance .

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

3
ответ дан 01.10.2019, 15:20
  • 1
    Это не удалило старых плагинов для меня (Eclipse 3.7, даже делая eclipse -clean впоследствии). – Philipp Wendler 03.10.2019, 08:09

Отражение - то, что Вы хотите. Отражение + TypeConverter. Не имейте намного большего количества времени, чтобы объяснить, но просто погуглить тех, и необходимо хорошо быть на пути. Или Вы могли просто использовать xml сериализатор, но тогда необходимо придерживаться формата, но работает отлично.

0
ответ дан 01.10.2019, 15:20
  • 1
    Хорошо, можно попробовать к ' move' те плагины от затмения/плагинов и затмения/функции к dropins/FileSync/eclipse / (plugins|features) и dropins/AJDT/eclipse/... и так далее. И посмотрите, можно ли лучше управлять плагинами оттуда. – VonC 03.10.2019, 08:07

Теги

Похожие вопросы