protected virtual void HandleRecovery(JsonSettings sender, RecoveryAction action, ref bool recovered, ref bool handled) { //versions mismatch, handle if (recovered || handled) { return; } switch (action) { case RecoveryAction.Throw: throw new JsonSettingsRecoveryException($"Loading {sender._childtype.Name} settings{(sender is IVersionable v ? $" version '{v.Version}'" : "")}"); case RecoveryAction.RenameAndLoadDefault: { if (loadedPath == null) { throw new ArgumentNullException(nameof(loadedPath)); } //parse current name var versionMatch = VersioningModule.VersionMatcher.Match(loadedPath); int fileVersion = versionMatch.Success ? int.Parse(versionMatch.Groups[2].Value) + 1 : 0; var cleanName = loadedPath; if (!string.IsNullOrEmpty(versionMatch.Groups[0].Value)) { cleanName = cleanName.Replace(versionMatch.Groups[0].Value, ""); } var lastIdx = cleanName.LastIndexOf('.'); if (lastIdx == -1) { lastIdx = loadedPath.Length; } uint nonVersionable = 0; //figure naming of existing and rename string newFileName = cleanName; if (File.Exists(newFileName)) { do { newFileName = cleanName.Insert(lastIdx, $".{(sender is IVersionable versionable ? versionable.Version : "")}{(fileVersion++ == 0 ? "" : $"-{fileVersion}")}"); } while (File.Exists(newFileName)); try { File.Move(cleanName, newFileName); } catch (Exception) { // swallow try { File.Delete(loadedPath); } catch (Exception) { // swallow } } } //save internalCalls++; try { sender.FileName = loadedPath = cleanName; sender.LoadDefault(ConstructingParameters); sender.Save(); recovered = true; handled = true; } finally { internalCalls--; } return; } case RecoveryAction.LoadDefault: sender.LoadDefault(ConstructingParameters); recovered = true; handled = true; return; case RecoveryAction.LoadDefaultAndSave: sender.LoadDefault(ConstructingParameters); sender.Save(); recovered = true; handled = true; return; default: throw new ArgumentOutOfRangeException(); } }