2010-01-06 3 views
1

Предположим, у меня есть класс CarResource, класс RaceCarResource: public CarResource, и класс SuperDuperUltraRaceCarResource: public RaceCarResource.C#: ручное чтение конфигурации XML для производных классов

Я хочу иметь возможность загружать их данные одним методом LoadFromXML.

Как я могу получить CarResource: LoadFromXML для загрузки его данных, RaceCarResource для вызова CarResource: LoadFromXML, а затем загрузить его собственные дополнительные данные и т. Д.?

Если я использую XmlTextReader я только знаю, как разобрать весь файл на одном дыхании, не так, как использовать его так первый CarResource: LoadFromXML может делать свое дело, а затем RaceCarResource и т.д.

Я надеюсь, что в хотя бы немного понятно, что я имею в виду :)

ответ

1
public class CarResource 
{ 
    public virtual void LoadFromXML(String xmlData) 
    { 
     ... 
    } 
} 

public class RaceCarResource : CarResource 
{ 
    public override void LoadFromXML(String xmlData) 
    { 
     base.LoadFromXML(xmlData); 
     ... 
    } 
} 

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

Что касается собственно анализа XML, у вас есть несколько вариантов. Мое первое предложение состояло в том, чтобы прочитать весь XML-файл в памяти ... и затем использовать LINQ to XML для анализа и заполнения ваших классов. Вы также можете попробовать XmlSerializer (LINQ to XML проще реализовать, но по мере роста размера вашей кодовой базы Xml Serialization упрощает обслуживание).

+0

Но как я могу действовать читать файл xml и позволить CarResource анализировать только свои собственные данные и позволить RaceCarResource самостоятельно анализировать свои собственные данные? – Pygmy

+0

Почему бы просто не сделать метод базового класса виртуальным? Подклассы затем переопределили бы виртуальный вызов по мере необходимости и все еще смогут вызвать реализацию базовых классов. – NotMe

+0

@ Крис - Зависит. Я обновил свой ответ, потому что вы правы, в этом случае имеет смысл создавать классы таким образом ... но проверьте эту ссылку: http://msdn.microsoft.com/en-us/library/6fawty39. aspx –

0

Вы также можете использовать XML-сериализацию в зависимости от структуры вашего XML-файла для загрузки. Можно переопределить метод загрузки (а затем переопределить в последующих классах) для загрузки определенной информации - или просто использовать атрибуты. См.: http://msdn.microsoft.com/en-us/library/ms950721.aspx

0

У вас есть несколько вариантов.

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

Вы можете использовать xmlnavigator, снова только проходя соответствующие дочерние узлы ... см: Implementing my own XPathNavigator in C#

Вы могли бы просто использовать XML-сериализации (XMLSERIALIZE XmlDeserialize), см C# - How to xml deserialize object itself?

0

Для того, чтобы использовать XML де-сериализация, метод экземпляра делает текущий объект эффективен «неизменным», но я хотел бы предложить что-то вроде этого:

public class CarResource 
{ 
    public CarResource LoadNewFromXML(string xml) 
    { 
     XmlSerializer ser = new XmlSerializer(this.GetType()); 
     object o = null; 
     using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(xml))) 
     { 
      o = ser.Deserialize(ms); 
     } 
     return o as CarResource; 
    } 
} 

public class RaceCarResource : CarResource 
{ 
} 

public class SuperRaceCarResource : RaceCarResource 
{ 
} 

Вашего вызывающего кода в п выглядит следующим образом:

RaceCarResource car = new RaceCarResource(); 
car = car.LoadNewFromXML("<RaceCarResource/>") as RaceCarResource; 

SuperRaceCarResource sc = new SuperRaceCarResource(); 
sc = sc.LoadNewFromXML("<SuperRaceCarResource/>") as SuperRaceCarResource; 
0

Если XML не совместим с .net XML сериализации, то самый простой способ создать завод, который определяет, какой тип ресурса представляет собой XML, а затем обрабатывает, что соответствующим образом. Если вы хотите поместить разбор в свои объекты, а затем использовать виртуальный метод для анализа внутренностей после создания объекта:

class CarResource 
{ 
    public string Color { get; private set; } 

    internal virtual void ReadFrom(XmlReader xml) 
    { 
     this.Color = xml.GetAttribute("colour"); 
    } 
} 

class RaceCarResource : CarResource 
{ 
    public string Sponsor { get; private set; } 

    internal override void ReadFrom(XmlReader xml) 
    { 
     base.ReadFrom(xml); 
     this.Sponsor = xml.GetAttribute("name-on-adverts"); 
    } 
} 

class SuperDuperUltraRaceCarResource : RaceCarResource 
{ 
    public string Super { get; private set; } 

    internal override void ReadFrom(XmlReader xml) 
    { 
     base.ReadFrom(xml); 
     this.Super = xml.GetAttribute("soup"); 
    } 
} 

class CarResourceFactory 
{ 
    public CarResource Read(XmlReader xml) 
    { 
     CarResource car; 

     switch (xml.LocalName) 
     { 
      case "ordinary-car": car = new CarResource(); break; 
      case "racecar": car = new RaceCarResource(); break; 
      case "super_duper": car = new SuperDuperUltraRaceCarResource(); break; 
      default: throw new XmlException(); 
     } 

     XmlReader sub = xml.ReadSubtree(); 

     car.ReadFrom(sub); 

     sub.Close(); 

     return car; 
    } 
} 

Это работает нормально, если XML для подтипа имеет дочерние элементы добавляемые строго после или до содержимого для супертипа.В противном случае вам придется больше работать, чтобы повторно использовать сериализацию супертипа, разбивая его на более мелкие методы (например, в базе есть методы для загрузки количества колес, дверей, размера двигателя, гоночный автомобиль звонит LoadDoorData, LoadAeroFoilData, LoadWheelData, если XML для гоночного автомобиля содержит данные аэрофотосъемки между данными о дверях и колесах. Для форматов без логического упорядочения (XMI, RDF) вы должны проверить локальное имя, чтобы решить, какой специализированный метод для вызова, который становится немного беспорядочным, если вы хотите объединить его с виртуальными методами. В этом случае лучше использовать отдельный помощник сериализации.

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