1

假设我有 CarResource 类、RaceCarResource 类:公共 CarResource 和 SuperDuperUltraRaceCarResource 类:公共 RaceCarResource。

我希望能够使用单个方法 LoadFromXML 加载他们的数据。

我将如何让 CarResource:LoadFromXML 加载它的数据,RaceCarResource 调用 CarResource:LoadFromXML 然后加载它自己的附加数据等?

如果我使用 XmlTextReader,我只知道如何一次性解析整个文件,而不知道如何使用它,所以首先 CarResource:LoadFromXML 可以做它的事情,然后是 RaceCarResource 等等。

我希望我的意思至少有点清楚:)

4

5 回答 5

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

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

...等等。new 关键字将隐藏继承的方法,但仍允许从子类调用它。

至于实际解析 XML,您有几个选择。我的第一个建议是将整个 XML 文件读入内存……然后使用 LINQ to XML 解析并填充您的类。您也可以尝试 XmlSerializer(LINQ to XML 更容易实现,但随着代码库大小的增长,Xml 序列化可以使维护更容易)。

于 2010-01-06T16:17:48.943 回答
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, LoadAeroFoilDataLoadWheelData如果用于赛车在车门和车轮数据之间有翼型数据。对于没有强加逻辑顺序的格式(XMI,RDF),您必须检查本地名称来决定调用哪个专用方法,如果您想调用它会有点混乱将它与虚拟方法结合起来。在这种情况下,最好使用单独的序列化助手。

如果要创建的类型集不固定为几种类型,则可以在工厂中使用其他机制。

于 2010-01-06T18:08:39.237 回答
0

您还可以根据要从中加载的 XML 文件的结构使用 XML 序列化。可以覆盖 load 方法(然后在后续类中覆盖)以加载特定信息 - 或仅使用属性。请参阅:http: //msdn.microsoft.com/en-us/library/ms950721.aspx

于 2010-01-06T16:20:29.127 回答
0

你有几个选择。

您可以使用 Linq to XML 查询子实体并将这些节点传递给您的其他类。这可能是最有效的方法。

您可以使用 xmlnavigator,再次仅传递适当的子节点...请参阅:Implementing my own XPathNavigator in C#

您可以简单地使用 xml 序列化 (XmlSerialize XmlDeserialize),请参阅C# - 如何 xml 反序列化对象本身?

于 2010-01-06T16:21:35.693 回答
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;
于 2010-01-06T16:52:17.470 回答