11using EnumerableToolkit ;
22using HarmonyLib ;
33using MonkeyLoader . Meta ;
4- using MonkeyLoader . Patching ;
54using System ;
65using System . Collections . Generic ;
76using System . ComponentModel ;
@@ -100,6 +99,11 @@ public abstract class MonkeySyncObject<TSyncObject, TSyncValue, TLink> : IUnlink
10099 /// </summary>
101100 protected static readonly Dictionary < string , Func < TSyncObject , TSyncValue > > propertyAccessorsByName = new ( StringComparer . Ordinal ) ;
102101
102+ /// <summary>
103+ /// The <typeparamref name="TSyncValue"/> instances associated with this sync object.
104+ /// </summary>
105+ protected readonly HashSet < TSyncValue > syncValues = [ ] ;
106+
103107 private bool _disposedValue ;
104108
105109 /// <inheritdoc/>
@@ -217,19 +221,26 @@ protected virtual bool EstablishLink(bool fromRemote)
217221 /// Creates a link for the given sync value of the given name.
218222 /// </summary>
219223 /// <remarks>
220- /// <i>By default:</i> Calls
221- /// <c><paramref name="syncValue"/>.<see cref="IUnlinkedMonkeySyncValue{TLink}.EstablishLinkFor">EstablishLinkFor</see>()</c>.
224+ /// <i>By default:</i> Adds the given sync value to the <see cref="syncValues">set of instances</see> and calls
225+ /// <c><paramref name="syncValue"/>.<see cref="IUnlinkedMonkeySyncValue{TLink}.EstablishLinkFor">EstablishLinkFor</see>(… )</c>.
222226 /// </remarks>
223227 /// <param name="syncValue">The sync value to link.</param>
224228 /// <param name="propertyName">The name of the sync value to link.</param>
225229 /// <param name="fromRemote">Whether the link is being established from the remote side.</param>
226230 /// <returns><c>true</c> if the link was successfully created; otherwise, <c>false</c>.</returns>
227231 protected virtual bool EstablishLinkFor ( TSyncValue syncValue , string propertyName , bool fromRemote )
228- => syncValue . EstablishLinkFor ( this , propertyName , fromRemote ) ;
232+ {
233+ syncValues . Add ( syncValue ) ;
234+ return syncValue . EstablishLinkFor ( this , propertyName , fromRemote ) ;
235+ }
229236
230237 /// <summary>
231238 /// Creates a link for the given sync method of the given name.
232239 /// </summary>
240+ /// <remarks>
241+ /// Any <typeparamref name="TSyncValue"/>s created for this
242+ /// must be added to the <see cref="syncValues">set of instances</see>.
243+ /// </remarks>
233244 /// <param name="syncMethod">The sync method to link.</param>
234245 /// <param name="methodName">The name of the sync method to link.</param>
235246 /// <param name="fromRemote">Whether the link is being established from the remote side.</param>
@@ -240,10 +251,15 @@ protected virtual bool EstablishLinkFor(TSyncValue syncValue, string propertyNam
240251 /// Cleans up any managed resources as part of <see cref="Dispose()">disposing</see>.
241252 /// </summary>
242253 /// <remarks>
243- /// <i>By default:</i> Disposes the <see cref="LinkObject">LinkObject</see> if it's <see cref="IDisposable"/>.
254+ /// <i>By default:</i> Disposes all <typeparamref name="TSyncValue"/> instances
255+ /// that were added to the <see cref="syncValues">set of instances</see>,
256+ /// and the <see cref="LinkObject">LinkObject</see> if it's <see cref="IDisposable"/>.
244257 /// </remarks>
245258 protected virtual void OnDisposing ( )
246259 {
260+ foreach ( var syncValue in syncValues )
261+ syncValue . Dispose ( ) ;
262+
247263 if ( LinkObject is IDisposable disposable )
248264 disposable . Dispose ( ) ;
249265 }
@@ -294,9 +310,9 @@ protected void OnPropertyChanged(string propertyName)
294310 }
295311
296312 /// <remarks><para>
297- /// <i>By default:</i> Calls <see cref="TryRestoreLinkFor(TSyncValue, string )">TryRestoreLinkFor</see>
313+ /// <i>By default:</i> Calls <see cref="TryRestoreLinkFor(TSyncValue)">TryRestoreLinkFor</see>
298314 /// for every readable <typeparamref name="TSyncValue"/> instance property and
299- /// <see cref="TryRestoreLinkFor(TSyncValue , string)">its overload</see> for every
315+ /// <see cref="TryRestoreLinkFor(Action{TSyncObject} , string)">its overload</see> for every
300316 /// <see cref="MonkeySyncMethodAttribute">MonkeySync method</see> on <typeparamref name="TSyncObject"/>.<br/>
301317 /// The detected properties are stored in <see cref="propertyAccessorsByName">propertyAccessorsByName</see>,
302318 /// while the detected methods are stored in <see cref="methodsByName">methodsByName</see>.
@@ -312,24 +328,26 @@ protected virtual bool TryRestoreLink()
312328 {
313329 var success = true ;
314330
315- foreach ( var syncValueProperty in propertyAccessorsByName )
316- success &= TryRestoreLinkFor ( syncValueProperty . Value ( ( TSyncObject ) this ) , syncValueProperty . Key ) ;
331+ foreach ( var syncValues in propertyAccessorsByName . Values )
332+ success &= TryRestoreLinkFor ( syncValues ( ( TSyncObject ) this ) ) ;
317333
318334 foreach ( var syncMethod in methodsByName )
319335 success &= TryRestoreLinkFor ( syncMethod . Value , syncMethod . Key ) ;
320336
321337 return success ;
322338 }
323339
324- // Implement the sync value one through a method on sync values
325-
326340 /// <summary>
327- /// Tries to restore the link for the given sync value of the given name .
341+ /// Tries to restore the link for the given sync value.
328342 /// </summary>
343+ /// <remarks>
344+ /// <i>By default:</i> Calls
345+ /// <c><paramref name="syncValue"/>.<see cref="ILinkedMonkeySyncValue{TLink}.TryRestoreLink">TryRestoreLink</see>()</c>.
346+ /// </remarks>
329347 /// <param name="syncValue">The sync value to link.</param>
330- /// <param name="propertyName">The name of the sync value to link.</param>
331348 /// <returns><c>true</c> if the link was successfully restored; otherwise, <c>false</c>.</returns>
332- protected abstract bool TryRestoreLinkFor ( TSyncValue syncValue , string propertyName ) ;
349+ protected virtual bool TryRestoreLinkFor ( TSyncValue syncValue )
350+ => syncValue . TryRestoreLink ( ) ;
333351
334352 /// <summary>
335353 /// Tries to restore the link for the given sync method of the given name.
0 commit comments