LINQ: загрузка XML в словарь со значением, равным новым экземплярам пользовательских классов

Немного борюсь с двумя утверждениями LINQ здесь. В основном я хотел бы преобразовать следующие два XML-файла в словари (тип-детали, чтобы следовать). Вот снимки XML:

Смещение XML:

<Offsets>
  <PlayerStructBase>0xF24C10</PlayerStructBase>
  <HP>
    <offset>0x17e8</offset>
  </HP>
  <MaxHP>
    <offset>0x17ec</offset>
  </MaxHP>
</Offsets>

Желаемый результат: Dictionary<string, IntPtr>, У меня есть метод с именем GetPointerFromBaseOffsets (смещение int[]), который возвращает IntPtr из массива int со смещением (пример: 0x1234, 0x17e2).

Навыки XML:

<Skills>
  <Potion>
    <Cast>0.00</Cast>
    <ReCast>60.00</ReCast>
    <MPCost>0</MPCost>
  </Potion>
  <Ruin>
    <Cast>2.49</Cast>
    <ReCast>2.49</ReCast>
    <MPCost>9</MPCost>
  </Ruin>
</Skills>

Желаемый результат: Dictionary<string, Skill>, Skill - это класс со свойствами Cast, ReCast и MpCost.


Это мои попытки:

Смещение XML в словарь

OffsetDictionary =
    XDocument.Load(folderPath+@"\offsets.xml")
        .XPathSelectElements("/Offsets/*[offset]")
        .ToDictionary(o => o.Name.LocalName,
            o => MemoryManager.GetPointerFromBaseOffsets(Enumerable.Cast<int>(o.Elements()).ToArray()));

Навыки XML в словарь

SkillDictionary =
    XDocument.Load(folderPath + @"\skills.xml")
        .XPathSelectElements("/Skills/*")
        .ToDictionary(e => e.Name.LocalName, e => new Skill(e.Name.LocalName, (double)e.Element("Cast"), (double)e.Element("ReCast"), (int)e.Element("MPCost")));

Вопрос: При попытке создать словарь смещения я получаю свое первое сообщение об ошибке (во время выполнения), что оно не может быть преобразовано. Может ли кто-нибудь показать мне, как написать эти два блока?

Спасибо!

1 ответ

Решение

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

OffsetDictionary =
    XDocument.Load(folderPath+@"\offsets.xml")
        .XPathSelectElements("/Offsets/*[offset]")
        .ToDictionary(o => o.Name.LocalName,
            o => MemoryManager.GetPointerFromBaseOffsets(o.Elements()
                                                          .Select(x => (int) x)
                                                          .ToArray()));

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

.Select(x => int.Parse(x.Value.Substring(2), NumberStyles.AllowHexSpecifier))

Или измените свой формат XML, чтобы значения были в десятичном виде.

Я не уверен насчет вашего выражения XPath... Я ни в коем случае не эксперт XPath, но разве вы не хотите, чтобы все элементы находились непосредственно под корневым элементом? Если это так, вы можете просто использовать

.Root.Elements()

вместо вашего XPathSelectElements вызов.

Другие вопросы по тегам