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

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

 

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

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

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

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

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

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

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

редактировать

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

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

Я бы также предложил сериализацию Xml, как уже упоминалось в других. Вот образец, который я собрал, чтобы продемонстрировать. Атрибуты используются для подключения имен из Xml к фактическим именам и типам свойств в структуре данных. Атрибуты также перечисляют все допустимые типы, которые могут войти в коллекцию Things . Все в этой коллекции должно иметь общий базовый class. Вы сказали, что у вас уже есть общий интерфейс, но вам, возможно, придется изменить это на абстрактный базовый class, потому что этот образец кода не сразу работал, когда 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 = "" + "" + "" + " " + " " + "" + ""; 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 things; public ThingCollection() { Things = new List(); } [XmlArray("stuff")] [XmlArrayItem(typeof(SomeThing))] [XmlArrayItem(typeof(SomeThingElse))] public List Things { get { return things; } set { things = value; } } } } 

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

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

 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; } 

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

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

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

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

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

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

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

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

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

Абстрактный шаблон заводского дизайна

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

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