Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 66 additions & 66 deletions src/Controls/src/Core/DepdendentHandle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,82 +15,82 @@ namespace System.Runtime;
/// </summary>
internal class DependentHandle : IDisposable
{
private readonly ConditionalWeakTable<object, object> _table;
private readonly WeakReference<object> _primaryRef;
private bool _disposed;
private readonly ConditionalWeakTable<object, object> _table;
private readonly WeakReference<object> _primaryRef;
private bool _disposed;

/// <summary>
/// Initializes a new instance of DependentHandle with a primary and dependent object.
/// </summary>
/// <param name="primary">The primary object that controls the lifetime of the dependent object.</param>
/// <param name="dependent">The dependent object that will be collected when primary is collected.</param>
public DependentHandle(object primary, object? dependent)
{
_table = new ConditionalWeakTable<object, object>();
_primaryRef = new WeakReference<object>(primary);
/// <summary>
/// Initializes a new instance of DependentHandle with a primary and dependent object.
/// </summary>
/// <param name="primary">The primary object that controls the lifetime of the dependent object.</param>
/// <param name="dependent">The dependent object that will be collected when primary is collected.</param>
public DependentHandle(object primary, object? dependent)
{
_table = new ConditionalWeakTable<object, object>();
_primaryRef = new WeakReference<object>(primary);

// Store the dependent object in the table, keyed by the primary object
if (dependent is not null)
{
_table.Add(primary, dependent);
}
}
// Store the dependent object in the table, keyed by the primary object
if (dependent is not null)
{
_table.Add(primary, dependent);
}
}

/// <summary>
/// Gets the primary object if it's still alive, otherwise returns null.
/// </summary>
public object? Target
{
get
{
if (_disposed)
return null;
/// <summary>
/// Gets the primary object if it's still alive, otherwise returns null.
/// </summary>
public object? Target
{
get
{
if (_disposed)
return null;

return _primaryRef.TryGetTarget(out var target) ? target : null;
}
}
return _primaryRef.TryGetTarget(out var target) ? target : null;
}
}

/// <summary>
/// Gets the dependent object if the primary object is still alive, otherwise returns null.
/// </summary>
public object? Dependent
{
get
{
if (_disposed)
return null;
/// <summary>
/// Gets the dependent object if the primary object is still alive, otherwise returns null.
/// </summary>
public object? Dependent
{
get
{
if (_disposed)
return null;

if (_primaryRef.TryGetTarget(out var primary) &&
_table.TryGetValue(primary, out var dependent))
{
return dependent;
}
if (_primaryRef.TryGetTarget(out var primary) &&
_table.TryGetValue(primary, out var dependent))
{
return dependent;
}

return null;
}
}
return null;
}
}

/// <summary>
/// Checks if both primary and dependent objects are still alive.
/// </summary>
public bool IsAllocated => Target is not null && Dependent is not null;
/// <summary>
/// Checks if both primary and dependent objects are still alive.
/// </summary>
public bool IsAllocated => Target is not null && Dependent is not null;

/// <summary>
/// Disposes the DependentHandleCWT, clearing all references.
/// </summary>
public void Dispose()
{
if (_disposed)
return;
/// <summary>
/// Disposes the DependentHandleCWT, clearing all references.
/// </summary>
public void Dispose()
{
if (_disposed)
return;

_disposed = true;
_disposed = true;

// Clear the table - this will allow dependent objects to be collected
// even if the primary object is still alive
if (_primaryRef.TryGetTarget(out var primary))
{
_table.Remove(primary);
}
}
// Clear the table - this will allow dependent objects to be collected
// even if the primary object is still alive
if (_primaryRef.TryGetTarget(out var primary))
{
_table.Remove(primary);
}
}
}
#endif
10 changes: 5 additions & 5 deletions src/Controls/tests/Core.UnitTests/CommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public void ExecuteDoesNotRunIfValueTypeAndSetToNull()
command.Execute(null); // "null is not a valid value for int"
Assert.True(executions == 0, "the command should not have executed");
}

[Theory]
[InlineData(typeof(Button), true)]
[InlineData(typeof(Button), false)]
Expand Down Expand Up @@ -294,10 +294,10 @@ public async Task CommandsSubscribedToCanExecuteCollect(Type controlType, bool u
case RefreshView r:
r.Command = command;
break;
case TextCell t:
case TextCell t:
t.Command = command;
break;
case ImageButton i:
case ImageButton i:
i.Command = command;
break;
case MenuItem m:
Expand All @@ -321,7 +321,7 @@ public async Task CommandsSubscribedToCanExecuteCollect(Type controlType, bool u
weakReferences.Add(new WeakReference(commandElement.CleanupTracker));
weakReferences.Add(new WeakReference(commandElement.CleanupTracker.Proxy));
}
else if(control is SearchHandler searchHandler)
else if (control is SearchHandler searchHandler)
{
// Add weak references to the command and its cleanup tracker
weakReferences.Add(new WeakReference(searchHandler.CommandSubscription));
Expand All @@ -343,7 +343,7 @@ public async Task CommandsSubscribedToCanExecuteCollect(Type controlType, bool u
Assert.True(weakRef.IsAlive);
}
}

foreach (var weakRef in weakReferences)
{
Assert.False(await weakRef.WaitForCollect());
Expand Down