Search code examples
c#dictionarycasting

C# How to Cast Dictionary<string, object> to a type?


I've run into this interesting issue where I get an System.InvalidCastException: 'Specified cast is not valid.' while trying to cast my object inside my Dictionary<string, object> to and (int). Inside this Dictionary I store state for the current Game someone is playing and want to re-save / re-load the data if the game requires a save or has been closed. This method is only for reading the save not saving it.

Many Thanks in Advance.

Code:

public async Task ReadGameFileInAsync(string gameVersion)
{
    var gameSave = new Dictionary<string, object>();
    if (gameVersion == "bronze")
        gameSave = JsonConvert.DeserializeObject<Dictionary<string, object>>(await ReadFileInAsync(BronzeGameSaveFilePath));
    else if (gameVersion == "silver")
        gameSave = JsonConvert.DeserializeObject<Dictionary<string, object>>(await ReadFileInAsync(SilverGameSaveFilePath));

    _GameStats.CurrentGame = (int)gameSave["CurrentGame"]; //Error throws here.
    _GameStats.CurrentWord = (int)gameSave["CurrentWord"];
    _GameStats.Score = (int)gameSave["Score"];
    _GameStats.BestScore = (int)gameSave["BestScore"];
    _GameStats.Difficulty = (int)gameSave["Difficulty"];
    _GameStats.IsNewGame = (bool)gameSave["IsNewGame"];
    _GameStats.IsContinue = (bool)gameSave["IsContinue"];
    _GameStats.IsUnlocked = (bool)gameSave["IsUnlocked"];
    _GameStats.GameVersion = (string)gameSave["GameVersion"];
    _GameStats.Cards = (ObservableCollection<LevelCardGroup>)gameSave["Cards"];
}

GameStats:

public class GameStats : IGameStats
{
    public int CurrentGame { get; set; } = 1;
    public int CurrentWord { get; set; } = 1;
    public int Score { get; set; } = 0;
    public int BestScore { get; set; } = 0;
    public bool IsNewGame { get; set; } = true;
    public bool IsContinue { get; set; } = false;
    public bool IsUnlocked { get; set; } = false;
    public bool ContinueButtonPressed { get; set; } = false;
    public string GameVersion { get; set; } = string.Empty;
    public int Difficulty { get; set; } = 3;
    public ObservableCollection<LevelCardGroup> Cards { get; set; } = new ObservableCollection<LevelCardGroup>();

    public void ResetGameStats(string gameVersion = "")
    {
        CurrentGame = 1;
        CurrentWord = 1;
        Score = 0;
        BestScore = 0;
        IsNewGame = true;
        IsContinue = false;
        GameVersion = gameVersion;
        Difficulty = 3;
        Cards.Clear();
    }
}

Solution

  • Just deserialize to the class instance and copy data from it:

    public async Task ReadGameFileInAsync(string gameVersion)
    {
        var gameSave = gameVersion switch
        {
            "bronze" => JsonConvert.DeserializeObject<GameStats>(await ReadFileInAsync(BronzeGameSaveFilePath)),
            "silver" => JsonConvert.DeserializeObject<GameStats>(await ReadFileInAsync(SilverGameSaveFilePath)),
            _ => null
        };
    
        if (gameSave is not null)
        {
            _GameStats.CurrentGame = gameSave.CurrentGame; // or maybe better create a copy from method
            //  ...
        }
        else
        {
            // todo: throw? clear game stats?
        }
    }