@@ -80,6 +80,31 @@ private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, Propert
8080 return SpecializedTasks . EmptyTask ;
8181 }
8282
83+ private object GetFirstOrDefaultValue ( OptionKey optionKey , IEnumerable < RoamingProfileStorageLocation > roamingSerializations )
84+ {
85+ // There can be more than 1 roaming location in the order of their priority.
86+ // When fetching a value, we iterate all of them until we find the first one that exists.
87+ // When persisting a value, we always use the first location.
88+ // This functionality exists for breaking changes to persistence of some options. In such a case, there
89+ // will be a new location added to the beginning with a new name. When fetching a value, we might find the old
90+ // location (and can upgrade the value accordingly) but we only write to the new location so that
91+ // we don't interfere with older versions. This will essentially "fork" the user's options at the time of upgrade.
92+
93+ foreach ( var roamingSerialization in roamingSerializations )
94+ {
95+ var storageKey = roamingSerialization . GetKeyNameForLanguage ( optionKey . Language ) ;
96+
97+ RecordObservedValueToWatchForChanges ( optionKey , storageKey ) ;
98+
99+ if ( _settingManager . TryGetValue ( storageKey , out object value ) == GetValueResult . Success )
100+ {
101+ return value ;
102+ }
103+ }
104+
105+ return optionKey . Option . DefaultValue ;
106+ }
107+
83108 public bool TryFetch ( OptionKey optionKey , out object value )
84109 {
85110 if ( _settingManager == null )
@@ -90,19 +115,15 @@ public bool TryFetch(OptionKey optionKey, out object value)
90115 }
91116
92117 // Do we roam this at all?
93- var roamingSerialization = optionKey . Option . StorageLocations . OfType < RoamingProfileStorageLocation > ( ) . SingleOrDefault ( ) ;
118+ var roamingSerializations = optionKey . Option . StorageLocations . OfType < RoamingProfileStorageLocation > ( ) ;
94119
95- if ( roamingSerialization == null )
120+ if ( ! roamingSerializations . Any ( ) )
96121 {
97122 value = null ;
98123 return false ;
99124 }
100125
101- var storageKey = roamingSerialization . GetKeyNameForLanguage ( optionKey . Language ) ;
102-
103- RecordObservedValueToWatchForChanges ( optionKey , storageKey ) ;
104-
105- value = _settingManager . GetValueOrDefault ( storageKey , optionKey . Option . DefaultValue ) ;
126+ value = GetFirstOrDefaultValue ( optionKey , roamingSerializations ) ;
106127
107128 // VS's ISettingsManager has some quirks around storing enums. Specifically,
108129 // it *can* persist and retrieve enums, but only if you properly call
@@ -222,7 +243,7 @@ public bool TryPersist(OptionKey optionKey, object value)
222243 }
223244
224245 // Do we roam this at all?
225- var roamingSerialization = optionKey . Option . StorageLocations . OfType < RoamingProfileStorageLocation > ( ) . SingleOrDefault ( ) ;
246+ var roamingSerialization = optionKey . Option . StorageLocations . OfType < RoamingProfileStorageLocation > ( ) . FirstOrDefault ( ) ;
226247
227248 if ( roamingSerialization == null )
228249 {
0 commit comments