1. Hi!

    I produce this in the config:
    Code:
      "Test": {
        "Test List": {
          "1": [
            "{playername} Test 1.",
            "{playername} Test 1.",
            "{playername} Test 1."
          ],
          "2": [
            "{playername} Test 2.",
            "{playername} Test 2.",
            "{playername} Test 2."
          ]
        },
      },
    
    With the code:
    Code:
            public static List<string> Alist = new List<string>
            {
                "{playername} Test 1.",
                "{playername} Test 1.",
                "{playername} Test 1."
            };
            public static List<string> Blist = new List<string>
            {
                "{playername} Test 2.",
                "{playername} Test 2.",
                "{playername} Test 2."
            };        public Dictionary<int, List<string>> TestList { get; private set; } = new Dictionary<int, List<string>>
            {
                {1, Alist},
                {2, Blist},
            };        private T GetConfig<T>(string category, string setting, T defaultValue)
            {
                var data = Config[category] as Dictionary<string, object>;
                object value;
                if (data == null)
                {
                    data = new Dictionary<string, object>();
                    Config[category] = data;
                    ConfigUpdated = true;
                }
                if (data.TryGetValue(setting, out value))
                {
                    return (T)Convert.ChangeType(value, typeof(T)); //**Error is thrown here**.
                }
                value = defaultValue;
                data[setting] = value;
                ConfigUpdated = true;
                return (T)Convert.ChangeType(value, typeof(T));
            }        private void LoadConfig()
            {
                TestList = GetConfig("Test", "Test List", TestList);
            }        void OnServerInitialized()
            {
                LoadConfig();
            }
    
    And when the plugin is reloaded and it tries to read that from the config it produces the following error:
    Code:
    Failed to call hook 'OnServerInitialized' on plugin 'GUIAnnouncements v1.21.68' (InvalidCastException: Value is not a convertible object: System.Collections.Generic.Dictionary`2[System.String,System.Object] to System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.List`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]])
    
    I'm sure the fix is quite simple but my brain is failing me at the moment, so any help is greatly appreciated.

    Thanks!
     
    Last edited by a moderator: Mar 15, 2017
  2. What does typeof(T) print?
     
  3. typeof(T) prints:
    Code:
    System.Collections.Generic.Dictionary`2[System.Int32,System.Collections.Generic.List`1[System.String]]
    
    I also did object value:
    Code:
    System.Collections.Generic.Dictionary`2[System.String,System.Object]
    
     
  4. Convert.ChangeType is presumably just a shallow conversion, i.e. it converts the type of the value, but not the type of each of the values stored in that value.
     
  5. What would be the best way to go about converting the values stored within which supposedly would be the items in the list?
     
  6. Would I need to "manually" rebuild the object which in this case is a dictionary containing lists as values, into a new dictionary and set it to the variable I am using my code to read from?
     
  7. Would Oxide's DynamicConfigFile.cs be able to handle that cast? I can't even remember why I stopped using it.
     
  8. I had this same issue also for a while, but now I just create a wrapper class to contain the data dictionaries in my plugins and just do a ReadObject/WriteObject to load/save the config. The casting/type assignment seems to work fine that way.
     
  9. I had a look at yours and that seems to work brilliantly, however I was really aiming for a config rework in my next update to make it a bit easier to understand, so the GetConfig("Category", "Setting") was working great for that.

    I ended up with the following to get what I wanted though:
    Code:
           public Dictionary<int, List<object>> newPlayerAnnouncementsList { get; private set; } = new Dictionary<int, List<object>>
            {
                {1, new List<object>{ "1st Join {playername} New player announcement 1.", "1st Join {playername} New player announcement 2.", "1st Join {playername} New player announcement 3." } },
                {2, new List<object>{ "2nd Join {playername} New player announcement 1.", "2nd Join {playername} New player announcement 2.", "2nd Join {playername} New player announcement 3." } },
                {3, new List<object>{ "3rd Join {playername} New player announcement 1.", "3rd Join {playername} New player announcement 2.", "3rd Join {playername} New player announcement 3." } },
            };        private void LoadGUIAnnouncementsConfig()
            {
                newPlayerAnnouncementsList = GetConfig("New Player Announcements", "Announcements List (Show On This Many Joins : List To Show)", newPlayerAnnouncementsList);
            }        private T GetConfig<T>(string category, string setting, T defaultValue)
            {
                var data = Config[category] as Dictionary<string, object>;
                object value;
                if (data == null)
                {
                    data = new Dictionary<string, object>();
                    Config[category] = data;
                    ConfigUpdated = true;
                }
                if (data.TryGetValue(setting, out value))
                {
    //Added this if statement
                    if (setting == "Announcements List (Show On This Many Joins : List To Show)")
                    {
                        var keyType = typeof(T).GetGenericArguments()[0];
                        var valueType = typeof(T).GetGenericArguments()[1];
                        var dict = (IDictionary)Activator.CreateInstance(typeof(T));
                        foreach (var key in ((IDictionary)value).Keys)
                        {
                            dict.Add(Convert.ChangeType(key, keyType), Convert.ChangeType(((IDictionary)value)[key], valueType));
                        }
                        return (T)dict;
                    }
                    return (T)Convert.ChangeType(value, typeof(T));
                }
                value = defaultValue;
                data[setting] = value;
                ConfigUpdated = true;
                return (T)Convert.ChangeType(value, typeof(T));
            }//Used later for changing the list to strings
            private List<string> ConvertObjectListToString(object value)
            {
                if (value is List<object>)
                {
                    List<object> list = (List<object>)value;
                    List<string> strings = list.Select(s => (string)s).ToList();
                    return strings;
                }
                else return (List<string>)value;
            }        void OnServerInitialized()
            {
                LoadGUIAnnouncementsConfig();
            }
    
    The if statement I got from Oxide's Config.ConvertValue method which I initially tried calling, but for some reason could never get it to actually go through to the dictionary conversion part. I also tried changing the value (list) in the foreach part to string there but it would just fail and not give me any errors so I just handle that later instead and changed the list in my dictionary to objects.

    (I also can't seem to change this thread to solved for some reason)