I am creating a Unity custom window, This window displays data from from an object that will eventually be converted to JSON
.
I am able to read the data and modify it as long as it isn't an array which is where I am having issues.
The data looks like this:
public static class GameData {
private static SaveData data;
public static SaveData save { get { return data.save; } }
[System.Serializable]
public class SaveData {
public int energyCurrent = 100;
public float speed = 2.5f;
public List<int> itm = new List<int>() { 1, 2, 3, 4, 5, 6 };
}
}
I then have an object which stores each item like this (where they key is the field name and value is the field value; ex: key=speed
, value=2.5f
):
class KeyValue {
public string key;
public object value;
public KeyValue(string key, object value) {
this.key = key;
this.value = value;
}
}
It is then stored within a list:
List<KeyValue> keyValues = new List<KeyValue>();
The part I am having issues with is the save which looks like this:
void SaveDataLocal() {
keyValues.ForEach(item => {
// GameData.save is a reference to SaveData
var field = GameData.save.GetType().GetField(item.key);
field.SetValue(GameData.save, GetValue(item));
});
GameData.Save();
}
object GetValue(KeyValue keyVal) {
var value = keyVal.value;
if (value.GetType().IsArray || isList(value)) {
List<object> list = new List<object>();
((List<KeyValue>)value).ForEach(item => {
list.add(GetValue(item));
});
return list;
} else {
return value;
}
}
I have tried two ways to update the value, however, I am getting an error saying:
ArgumentException: Object type System.Collections.Generic.List`1[System.Object] cannot be converted to target type: System.Collections.Generic.List`1[System.Int32]
I am trying to use Reflection because list type could be int
, float
, Vector3
, etc. so I need it to by dynamic, and I cannot use a dynamic type because we are not using 4.x
.
The error is taking place here:
field.SetValue(GameData.save, GetValue(item));
GetValue()
returning a List<object>
when the field is a List<int>
. What can I do to pass the List<object>
?
I have tried casting it like so:
public static T Cast<T>(object o) {
return (T)o;
}
keyValues.ForEach(item => {
var field = GameData.save.GetType().GetField(item.key);
var val = GetValue(item);
var castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(field.FieldType);
var r = castMethod.Invoke(null, new object[] { val });
field.SetValue(GameData.save, r);
});
But I am getting this error:
InvalidCastException: Cannot cast from source type to destination type. GameSmart.SaveData.Cast[List`1]
I am not sure if this is the cleanest way, but I basically had to do a cast by looping over all the items in the list/array and individually casting them. I can't seem to cast an entire list at once.
public static List<T> CastList<T>(List<object> o) {
var list = new List<T>();
foreach (var i in o) { list.Add((T)i); }
return list;
}
void SaveDataLocal() {
keyValues.ForEach(item => {
var field = GameData.save.GetType().GetField(item.key);
var value = GetValue(item);
if (value.GetType().IsArray || isList(value)) {
Type type;
if (isList(value)) type = field.FieldType.GetGenericArguments().Single();
else type = field.FieldType.GetElementType();
var castMethod = this.GetType().GetMethod("CastList").MakeGenericMethod(type);
value = castMethod.Invoke(null, new object[] { value });
}
field.SetValue(GameData.save, value);
});
GameData.Save();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.