Laden...

LINQ to XML: Liste von child objects als Eigenschaft. Anonymes Objekt richtig ansprechen...

Erstellt von *Andreas* vor 6 Jahren Letzter Beitrag vor 6 Jahren 1.782 Views
*
*Andreas* Themenstarter:in
15 Beiträge seit 2012
vor 6 Jahren
LINQ to XML: Liste von child objects als Eigenschaft. Anonymes Objekt richtig ansprechen...

Hallo,

ich verwende folgenden Code um eine Liste von Objekten zu erhalten:

var getmks247Task = (from deviceElem in XDocument.Load(xmlRdr).Element("devices").Elements("device")
                                     where (string)deviceElem.Attribute("type") == "mks247"
                                     select new // => see the new keyword for the object declaration
                                     {
                                         mks247dev = CreateAndConnectTomks247Async(
                                             (string)deviceElem.Attribute("ip"),
                                             (string)deviceElem.Attribute("name"),
                                             (string)deviceElem.Attribute("id"),
                                             (bool)deviceElem.Attribute("autoconnect")),
                                         Calibrations = (from calibrationElem in deviceElem.Descendants("calibration")
                                                         select new mks247VolumetricConverter((decimal)calibrationElem.Attribute("a"), (decimal)calibrationElem.Attribute("b"))
                                                         {
                                                             Name = (string)calibrationElem.Attribute("name"),
                                                             //Unit = (string)calibrationElem.Attribute("name"),
                                                         }).ToList<mks247VolumetricConverter>(),
                                     });

                var mks247s = await Task.WhenAll(getmks247Task.Select(x => x.mks247dev).ToArray());

Mein Problem ist: Calibrations ist eigentlich eine Eigenschaft von mks247dev. D.h. ich hätte eigentlich gerne sowas wie mks247dev.Calibrations = ... Das erlaubt er mir aber (aus nachvollziehbaren Gründen) nicht.

Der Vollständigkeit halber Code der CreateAndConnectTomks247Async:

 private async Task<mks247Device> CreateAndConnectTomks247Async(string host, string name, string id, bool autoconnect = true)
        {
            mks247Device dev = new mks247Device(host, name, id);
            // Register it with View Model.
            // TODO: Handle that better OOP-like using events.
            vm.RegisterDevice(dev);

            if (autoconnect)
            {
                if (await dev.ConnectAsync())
                    dev.BeginPolling();
            }

            return dev;
        }

Herzlichen Dank für eure Hilfe!

LG,
Andreas

2.080 Beiträge seit 2012
vor 6 Jahren

Wenn ich dich richtig verstanden habe, dann geht das nicht. Du brauchst die Methoden-Syntax dafür.

.Select(x =>
{
    var mks247dev = ...
    mks247dev.Calibrations = ...
    return mks247dev;
});

Ich persönlich würde das aber als foreach-Schleife schreiben. Darin erzeugst Du dann dein Objekt und kannst gleichzeitig auch das await darin verwenden, was in dem Select ja nicht geht.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

*
*Andreas* Themenstarter:in
15 Beiträge seit 2012
vor 6 Jahren

Hallo,

danke für deine Antwort. D.h. du meinst gar nicht mit LINQ to XML, sondern mit einer "ganz normalen" foreach-Schleife?

Stimmt, das ginge so relativ simpel: Bin da eventuell Opfer meines Drangs geworden, alles möglichst elegant zu machen...

Danke!

LG,
Andreas

16.842 Beiträge seit 2008
vor 6 Jahren

Wenn Du ein fixes XML Schema hast, dann nutze doch einfach Serialisierung.
Dann musst nix mehr von Hand machen und hast direkt eine Validierung.

*
*Andreas* Themenstarter:in
15 Beiträge seit 2012
vor 6 Jahren

Hallo,

danke für eure Tipps. Die Xml-Serialization fand ich immer mühsam und wenig anpassbar.

Aber ich habe es jetzt so gelöst (sollte jemand anders noch so ein ähnliches Problem haben):

    using (XmlReader xmlRdr = new XmlTextReader(deviceConfigPath))
            {
                XDocument xmlDoc = XDocument.Load(xmlRdr);
                // All the mks247 devices.
                var mks247devices = from d in xmlDoc.Descendants().Where(n => n.Name == "device" && (string)n.Attribute("type") == "mks247") select d;

                foreach (var device in mks247devices)
                {
                    // That's the device:
                    mks247Device dev = new mks247Device((string)device.Attribute("ip"), (string)device.Attribute("name"), (string)device.Attribute("id"));
                    // Now the calibrations:
                    IEnumerable<mks247VolumetricConverter> volumetricConverters = from v in device.Descendants("calibration")
                                                                                  select new mks247VolumetricConverter((decimal)v.Attribute("a"), (decimal)v.Attribute("b"), (string)v.Attribute("unit"))
                                                                                  {
                                                                                      Name = (string)v.Attribute("name"),
                                                                                  };

                    dev.Calibrations = new List<mks247VolumetricConverter>(volumetricConverters);

                    // TODO: Do that more OOP-way by registering via events:
                    vm.RegisterDevice(dev);

                    if ((bool)device.Attribute("autoconnect"))
                    {
                        if (await dev.ConnectAsync())
                            dev.BeginPolling();
                    }
                    // Add to our list.
                    deviceList.Add(dev as SmartCatDeviceBase);
                }
            } 

Danke noch einmal und danke für hilfreichen Tipps!

LG,
Andreas

16.842 Beiträge seit 2008
vor 6 Jahren

Mit dem Serialier wäre das eine handvoll Code. Weniger als das. Aber nun gut...

Zu Deinem Kommentar

// TODO: Do that more OOP-way by registering via events:

OOP deckt keine Architektur-Prinzipien wie Event based Actions ab 😉

*
*Andreas* Themenstarter:in
15 Beiträge seit 2012
vor 6 Jahren

Nur kann XmlSerialization nur public properties serialisieren. Außer natürlich ich implementiere erst recht die Schnittstelle.

Zu deinem Kommentar: Ja, allerdings habe ich hierdurch keine sonderlich gute Kapselung. Das wäre mit Events weit besser. Trotzdem bin ich dankbar, wenn solche Kommentare kommen, denn ich bin dann doch Chemiker, der sich seine Tools programmiert.

Daraus folgt aber auch, dass es weit bessere Programmierer hier gibt. 😉