Setting a property from a string

Hi,

I am serializing and deserializing items in my scene to save/load the items.
I have successfully serialized properties into a PropertyData object:

    [System.Serializable]
    public class PropertyData
    {
        public string Name;
        public string Type;
        public object Value;
    }

Here’s the serialization code:

public List<PropertyData> SerializeProperties()
        {
            var list = new List<PropertyData>();

            var type = this.GetType();

            var properties = type.GetProperties(/*blablabla*/);

            for(int i = 0; i < properties.Length; i++)
            {
                var property = properties[i];

                var data = new PropertyData();

                data.Name = property.Name;
                data.Type = property.PropertyType.FullName;
                data.Value = property.GetValue(this);

                list.Add(data);
            }

            return list;
        }

The list of PropertyData objects is then stored in another object that gets converted using Newtonsoft.JSON.

Here’s for example the result for a bool and a color property.

"Items": [
    {
      "Name": "My Serialized Item 1",
      "Id": "342354",
      ...
      "Properties": [
        {
          "Name": "Visible",
          "Type": "System.Boolean",
          "Value": false
        },
        {
          "Name": "Color",
          "Type": "UnityEngine.Color",
          "Value": {
            "r": 1.0,
            "g": 0.0,
            "b": 0.0,
            "a": 1.0,
            "grayscale": 0.299,
            "maxColorComponent": 1.0
          }
        }
      ]
    },
...
  ]
}

But now I can’t reverse the process properly. Here’s the deserialization code:

protected void DeserializePropertyData(PropertyData data)
        {
            var p = this.GetType().GetProperty(data.Name);

            if(p == null)
            {
                return;
            }

            var type = p.PropertyType;
          
            // SOMETHING NEEDS TO BE DONE TO CONVERT data.Value to the correct object

            p.SetValue(this, data.Value);
        }

This results in: ArgumentException: Object of type 'Newtonsoft.Json.Linq.JObject' cannot be converted to type 'UnityEngine.Color'

I’m kinda blank right now. Does anyone have an idea? Perhaps the whole approach is wrong?

Yeah, pretty sure that Newtonsoft’s got a built-in thing that does exactly what you’re trying to do. Your current code looks very manual.

Thanks for the response. A pointer in the right direction would be great; I haven’t found a good solution in the Newtonsoft docs. I’m trying to serialize/deserialize EventHandlers (which works with my manual approach) and Properties.

I mean, there’s a carousel in the upper right corner of their home page that shows what you need to do.
An important point is that you shouldn’t deserialize from inside the class getting deserialized - instead it should be some external thing building the object using JsonConvert.DeserializeObject

Yeah I think I figured it out. I have code to serialize/deserialize EventHandlers, because that is the primary information I want to save and reload; but for Properties I will just do it this way:

public class ItemData //Item is a MonoBehaviour, I store the data in a separate object
    {
        public string Name;

        public string Id;

        public List<EventHandlerData> Events = new List<EventHandlerData>(); //tthat's what I generate on my own
    }

And then for any other implementations of Items and ItemDatas I do this:

public class CustomItemData: ItemData
    {
        public Color ColorVisible;
        public Color ColorInvisible;
        public Color CurrentColor;

        public bool Visible;
    }

Then I can just let Newtonsoft do its magic with properly serializing and deserializing the objects. So, for example, I do this in the CustomItem : Item class:

public class CustomItem : Item //Item : MonoBehaviour
{
        public Color color;
        public Color colorVisible;
        public Color colorInvisible;
        public bool visible;

        public override ItemData SerializeData()
        {
            var data = new CustomItemData();

            AddBaseData(data);

            data.CurrentColor = this.color;
            data.ColorVisible = this.colorVisible;
            data.ColorInvisible = this.colorInvisible;
            data.Visible = this.visible;

            return data;
        }

        public override void DeserializeData(ItemData data)
        {
            base.DeserializeData(data);

            var custom = data as CustomItemData;

            if(custom == null)
            {
                return;
            }

            this.color = custom.CurrentColor;
            this.colorVisible = custom.ColorVisible;
            this.colorInvisible = custom.ColorInvisible;
            this.visible = custom.Visible;
        }

}

I thought it would be cool to not have to implement a custom ItemData class for every customization of my Item class. So that’s why I wanted a method in the Item class that iterates over all properties with a custom PropertyAttribute. But that doesn’t work out as stated in my first post.

I can’t directly serialize a MonoBehaviour, so I have to use the Memento pattern. But it really is tiresome to have to implement a custom ItemData class for every derivative of my Item class.