C#:手动读取派生类的 XML 配置

发布于 2024-08-17 03:52:44 字数 398 浏览 6 评论 0原文

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

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

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

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

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

Suppose I have class CarResource,
class RaceCarResource : public CarResource,
and class SuperDuperUltraRaceCarResource : public RaceCarResource.

I want to be able to load their data using a single method LoadFromXML.

How would I go about getting the CarResource:LoadFromXML to load it's data,
RaceCarResource to call CarResource:LoadFromXML and then load it's own additional data, etc. ?

If I use XmlTextReader I only know how to parse the entire file in one go,
not how to use it so first CarResource:LoadFromXML can do its thing, then RaceCarResource, etc.

I hope it's at least a little bit clear what I mean :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一口甜 2024-08-24 03:52:44
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 序列化可以使维护更容易)。

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

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

...and so on. The new keyword will hide the inheritted method but still allow it to be call-able from the child class.

As for actually parsing the XML, you have a couple of options. My first suggestion would be to read the entire XML file in to memory...and then use LINQ to XML to parse through and populate your classes. You could also try the XmlSerializer (LINQ to XML is easier to implement, but as the size of your code-base grows, Xml Serialization can make maintenance easier).

债姬 2024-08-24 03:52:44

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

You could also use XML Serialization depending on the structure of your XML file to load from. It's possible to override the load method (and then override in subsequent classes) to load specific information - or just use attributes. See: http://msdn.microsoft.com/en-us/library/ms950721.aspx

缱倦旧时光 2024-08-24 03:52:44

你有几个选择。

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

您可以使用 xmlnavigator,再次仅传递适当的子节点...
请参阅:在 C# 中实现我自己的 XPathNavigator

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

You have a couple of options.

You can use Linq to XML to query the child entities and pass those nodes to your other classes. This is probably the most efficient way of doing it.

You could use an xmlnavigator, again only passing the appropriate child nodes...
see: Implementing my own XPathNavigator in C#

You could simply use xml serialization (XmlSerialize XmlDeserialize), see C# - How to xml deserialize object itself?

简单 2024-08-24 03:52:44

为了使用 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;

In order to use XML de-serialization, the instance method makes the current object effectively 'immutable', but I would suggest something like this:

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

Your calling code then looks like:

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

SuperRaceCarResource sc = new SuperRaceCarResource();
sc = sc.LoadNewFromXML("<SuperRaceCarResource/>") as SuperRaceCarResource;
隔岸观火 2024-08-24 03:52:44

如果您的 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)。 结合起来,这会有点混乱,在这种情况下,最好使用单独的序列化助手。

你必须检查本地名称来决定调用哪个专门的方法,如果你想将它与虚拟方法 如果要创建的类型集不固定为几种类型,则为工厂。

If your XML is not compatible with the .net XML serialisation, then the easiest way is to create a factory which detects which type of resource the XML represents, then handles that appropriately. If you want to put the parsing into your objects, then use a virtual method to parse the internals after creating the object:

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

This works OK if the XML for a sub-type has any child elements appended strictly after or before the content for the super-type. Otherwise you have to do more work to reuse the super-type's serialisation, breaking it up into smaller methods (eg the base has methods to load the number of wheels, doors, engine size; the race car calls LoadDoorData, LoadAeroFoilData, LoadWheelData if the XML for the race car has the aerofoil data in between the door and wheel data. For formats with no logical ordering imposed (XMI, RDF) you have to inspect the local name to decide which specialised method to call, which gets a bit messy if you want to combine it with virtual methods. In that case, it's better to use a separate serialisation helper.

Other mechanisms can be used in the factory if the set of types to be created is not fixed to a few types.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文