2

I'm making an inventory system for a Unity game.

It serializes and saves the inventory to an xml file as expected; However, when I deserialize, the items are set to null and a TargetInvocationException is thrown; and ultimately a NullReferenceException.


What am I doing wrong?


Serialize and Deserialize Methods

public void SaveInventoryToXML()
{
    System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof (List<Item>));
    System.IO.StreamWriter file = new System.IO.StreamWriter(inventoryPath);
    writer.Serialize(file, inventory);
    file.Close();
}

public void LoadInventoryFromXML()
{
    System.Xml.Serialization.XmlSerializer reader = new System.Xml.Serialization.XmlSerializer(typeof(List<Item>));
    StreamReader sr = new StreamReader(inventoryPath);
    inventory = (List<Item>) reader.Deserialize(sr);
    sr.Close();
}

'Item' & 'Enchantment' Class

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

[System.Serializable] //what's with the square brackets
public class Item
{
    public string ItemName;
    public int ItemId;
    public string ItemDesc;
    public int BaseWorth;
    public int BaseDamage;
    public int RequiredLevel;
    public Sprite Sprite;
    public ItemType itemType;
    public ItemRarity itemRarity;
    public Weapon.WeaponType weaponType;
    public Weapon.AttackType attackType;
    public List<Enchantment> Enchantments;
    public bool Stackable;
    public int StackSize = 99;
    public int Amount = 1;

    public enum ItemType
    {
        Weapon, Consumable, Quest, Armor, Boots, Helmet, Gloves, Ring, Amulet
    }

    public enum ItemRarity
    {
        Common, Rare, Unique, Magic
    }

    public Item(string name, int id, int reqlvl, string desc, int baseworth, int basedamage, List<Enchantment> enchantments, ItemType itemtype, ItemRarity itemrarity, Sprite sprite )
    {
        ItemName = name;
        ItemId = id;
        RequiredLevel = reqlvl;
        ItemDesc = desc;
        BaseWorth = baseworth;
        BaseDamage = basedamage;
        Enchantments = enchantments;
        itemType = itemtype;
        itemRarity = itemrarity;
        Sprite = sprite;
        additionalParameters();
    }

    private void additionalParameters()
    {
        switch (itemType)
        {
            case ItemType.Consumable:
                Stackable = true;
                break;
        }
    }

    public Item()
    {
        ItemId = -1;
    }
}

public class Enchantment
{
    public EnchantmentType Type;
    public int Amount;
    public enum EnchantmentType
    {
        Fire, Ice, Poison, Electric, Brutalize, Greed, Invisiblity, Heal, ReplenishStamina, ReplenishMana,
        AddMaxHealth, AddMaxStamina, AddMaxMana
    }

    public Enchantment(EnchantmentType type, int amount)
    {
        Amount = amount;
        Type = type;
    }

    public Enchantment()
    {

    }
}

Call Stack

NullReferenceException
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232)
System.Reflection.MonoProperty.SetValue (System.Object obj, System.Object value, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] index, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoProperty.cs:348)
System.Reflection.PropertyInfo.SetValue (System.Object obj, System.Object value, System.Object[] index) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/PropertyInfo.cs:102)
System.Xml.Serialization.XmlTypeMapMember.SetValue (System.Object ob, System.Object value)
System.Xml.Serialization.XmlSerializationReaderInterpreter.SetMemberValue (System.Xml.Serialization.XmlTypeMapMember member, System.Object ob, System.Object value, Boolean isValueList)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, Boolean isValueList, Boolean readByOrder)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, Boolean isValueList, Boolean readByOrder)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObjectElement (System.Xml.Serialization.XmlTypeMapElementInfo elem)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadListElement (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, System.Object list, Boolean canCreateInstance)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot (System.Xml.Serialization.XmlTypeMapping rootMap)
System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot ()
System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.Serialization.XmlSerializationReader reader)

writer.Serializer

sampled output

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Item>
        <ItemName>Steel Sword</ItemName>
        <ItemId>102</ItemId>
        <ItemDesc>A fine steel sword.</ItemDesc>
        <BaseWorth>125</BaseWorth>
        <BaseDamage>25</BaseDamage>
        <RequiredLevel>10</RequiredLevel>
        <Sprite>
            <name>BasicWeapons_2</name>
            <hideFlags>NotEditable</hideFlags>
        </Sprite>
        <itemType>Weapon</itemType>
        <itemRarity>Rare</itemRarity>
        <weaponType>Sword</weaponType>
        <attackType>Swing</attackType>
        <Stackable>false</Stackable>
        <StackSize>99</StackSize>
        <Amount>1</Amount>
    </Item>
    <Item>
        <ItemName>Mithril Sword</ItemName>
        <ItemId>103</ItemId>
        <ItemDesc>Feels lighter than steel, yet much sharper...</ItemDesc>
        <BaseWorth>625</BaseWorth>
        <BaseDamage>125</BaseDamage>
        <RequiredLevel>25</RequiredLevel>
        <Sprite>
            <name>BasicWeapons_3</name>
            <hideFlags>NotEditable</hideFlags>
        </Sprite>
        <itemType>Weapon</itemType>
        <itemRarity>Unique</itemRarity>
        <weaponType>Sword</weaponType>
        <attackType>Swing</attackType>
        <Stackable>false</Stackable>
        <StackSize>99</StackSize>
        <Amount>1</Amount>
    </Item>
    <Item>
        <ItemId>-1</ItemId>
        <BaseWorth>0</BaseWorth>
        <BaseDamage>0</BaseDamage>
        <RequiredLevel>0</RequiredLevel>
        <itemType>Weapon</itemType>
        <itemRarity>Common</itemRarity>
        <weaponType>Sword</weaponType>
        <attackType>Swing</attackType>
        <Stackable>false</Stackable>
        <StackSize>99</StackSize>
        <Amount>1</Amount>
    </Item>
</ArrayOfItem>

File: http://a.pomf.se/avxuvz.xml

Brett Caswell
  • 1,486
  • 1
  • 13
  • 25

2 Answers2

2

I've just tried your code myself and I managed to get it working properly by removing the Sprite field. My guess is that this is your culprit, as it most likely cannot be serialized - so you may have to simply store the path to the sprite as a string or something similar.

var list = new List<Item>()
{
    new Item(),
    new Item()
};
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(List<Item>));

using (var stream = File.Open("Document.xml", FileMode.CreateNew))
{
    xmlSerializer.Serialize(stream, list);
}

using (var stream = File.Open("Document.xml", FileMode.Open))
{
    xmlSerializer.Deserialize(stream);
}

Produces the following output:

<?xml version="1.0"?>
<ArrayOfItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Item>
    <ItemId>-1</ItemId>
    <BaseWorth>0</BaseWorth>
    <BaseDamage>0</BaseDamage>
    <RequiredLevel>0</RequiredLevel>
    <itemType>Weapon</itemType>
    <itemRarity>Common</itemRarity>
    <Stackable>false</Stackable>
    <StackSize>99</StackSize>
    <Amount>1</Amount>
  </Item>
  <Item>
    <ItemId>-1</ItemId>
    <BaseWorth>0</BaseWorth>
    <BaseDamage>0</BaseDamage>
    <RequiredLevel>0</RequiredLevel>
    <itemType>Weapon</itemType>
    <itemRarity>Common</itemRarity>
    <Stackable>false</Stackable>
    <StackSize>99</StackSize>
    <Amount>1</Amount>
  </Item>
</ArrayOfItem>
1

Obviously not fun to do it manually, but you could try serialization via IXmlSerializable.

D. A. Terre
  • 6,092
  • 1
  • 18
  • 18