使用反射将动态类型添加到List <object>

时间:2019-02-06 16:49:47

标签: c# unity3d

我正在创建一个Unity自定义窗口,此窗口显示来自对象的数据,该对象最终将转换为JSON

只要不是我遇到问题的数组,我就能读取并修改数据。

数据如下:

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 };
    }
}

然后我有一个对象,可以像这样存储每个项目(它们的键是字段名,值是字段值;例如:key=speedvalue=2.5f):

class KeyValue {
    public string key;
    public object value;

    public KeyValue(string key, object value) {
        this.key = key;
        this.value = value;
    }
}

然后将其存储在列表中:

List<KeyValue> keyValues = new List<KeyValue>();

我遇到问题的部分是保存,如下所示:

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;
    }
}

我尝试了两种更新值的方法,但是,我收到一条错误消息:

  

ArgumentException:对象类型System.Collections.Generic.List`1 [System.Object]无法转换为目标类型:System.Collections.Generic.List`1 [System.Int32]

我正在尝试使用反射,因为列表类型可以是intfloatVector3等,所以我需要通过动态方式来使用它,而不能使用动态类型,因为我们没有使用4.x

此处发生错误:

field.SetValue(GameData.save, GetValue(item));

GetValue()在字段为List<object>时返回List<int>。如何通过List<object>

编辑

我尝试过像这样投射它:

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);
});

但是我收到此错误:

  

InvalidCastException:无法从源类型转换为目标类型。   GameSmart.SaveData.Cast [List`1]

1 个答案:

答案 0 :(得分:1)

我不确定这是否是最干净的方法,但是我基本上必须通过循环遍历列表/数组中的所有项目并分别进行转换来进行转换。我似乎无法一次投射整个列表。

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();
}