Files
I150/srcs/RobotNet10/RobotApp/Communication/CeresSharp/Native/ResourceManager.cs
2026-07-03 16:37:12 +07:00

121 lines
3.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace CeresSharp.Native;
/// <summary>
/// Helper class for managing GCHandle resources and ensuring proper cleanup.
/// Provides utilities for tracking and disposing of pinned handles.
/// </summary>
internal sealed class ResourceManager : IDisposable
{
private readonly List<GCHandle> _handles = new List<GCHandle>();
private bool _disposed;
/// <summary>
/// Adds a GCHandle to be managed and disposed.
/// </summary>
/// <param name="handle">The GCHandle to track.</param>
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
public void AddHandle(GCHandle handle)
{
if (_disposed)
throw new ObjectDisposedException(nameof(ResourceManager));
lock (_handles)
{
_handles.Add(handle);
}
}
/// <summary>
/// Adds multiple GCHandles to be managed and disposed.
/// </summary>
/// <param name="handles">The GCHandles to track.</param>
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
public void AddHandles(IEnumerable<GCHandle> handles)
{
if (_disposed)
throw new ObjectDisposedException(nameof(ResourceManager));
lock (_handles)
{
_handles.AddRange(handles);
}
}
/// <summary>
/// Pins an array and adds the handle to the manager.
/// </summary>
/// <typeparam name="T">The unmanaged type of the array elements.</typeparam>
/// <param name="array">The array to pin.</param>
/// <returns>The pinned GCHandle.</returns>
/// <exception cref="ArgumentNullException">Thrown when array is null.</exception>
/// <exception cref="ObjectDisposedException">Thrown when the manager is disposed.</exception>
public GCHandle PinArray<T>(T[] array) where T : unmanaged
{
if (array == null)
throw new ArgumentNullException(nameof(array));
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
AddHandle(handle);
return handle;
}
/// <summary>
/// Gets all handles as an array (for safe enumeration during disposal).
/// </summary>
/// <returns>Array of GCHandles.</returns>
public GCHandle[] GetHandlesSnapshot()
{
lock (_handles)
{
return _handles.ToArray();
}
}
/// <summary>
/// Clears all handles without disposing them.
/// Useful when ownership is transferred to another object.
/// </summary>
public void Clear()
{
lock (_handles)
{
_handles.Clear();
}
}
public void Dispose()
{
if (!_disposed)
{
// Get snapshot to avoid issues during enumeration
var handlesToFree = GetHandlesSnapshot();
lock (_handles)
{
_handles.Clear();
}
// Free handles outside the lock
foreach (var handle in handlesToFree)
{
try
{
if (handle.IsAllocated)
handle.Free();
}
catch
{
// Ignore errors during cleanup - handles may already be freed
}
}
_disposed = true;
}
}
}