Skip to content

Commit 3132bd6

Browse files
committed
Replace GCHandle with new types
.NET 10 introduced new strongly-typed GCHandle types.
1 parent 241c2de commit 3132bd6

9 files changed

Lines changed: 84 additions & 134 deletions

File tree

src/Godot.Bindings/Bridge/Callables/CustomCallable.cs

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ public abstract class CustomCallable : IDisposable
1717
{
1818
private bool _disposed;
1919

20-
private GCHandle _gcHandle;
20+
private GCHandle<CustomCallable> _gcHandle;
2121

2222
/// <summary>
2323
/// Constructs a <see cref="CustomCallable"/>.
2424
/// </summary>
2525
public CustomCallable()
2626
{
27-
_gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
27+
_gcHandle = new GCHandle<CustomCallable>(this);
2828

2929
DisposablesTracker.RegisterDisposable(this);
3030
}
@@ -41,7 +41,7 @@ internal unsafe NativeGodotCallable ConstructCallable()
4141
{
4242
var info = new GDExtensionCallableCustomInfo2()
4343
{
44-
callable_userdata = (void*)GCHandle.ToIntPtr(_gcHandle),
44+
callable_userdata = (void*)GCHandle<CustomCallable>.ToIntPtr(_gcHandle),
4545
token = GodotBridge.LibraryPtr,
4646
object_id = GetObjectId(),
4747
call_func = &Call_Native,
@@ -144,18 +144,16 @@ protected virtual void Dispose(bool disposing)
144144

145145
_disposed = true;
146146

147-
_gcHandle.Free();
147+
_gcHandle.Dispose();
148148
}
149149

150150
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])]
151151
private static unsafe void Call_Native(void* userData, NativeGodotVariant** args, long argsCount, NativeGodotVariant* outRet, GDExtensionCallError* outError)
152152
{
153153
try
154154
{
155-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
156-
var callable = (CustomCallable?)gcHandle.Target;
157-
158-
Debug.Assert(callable is not null);
155+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
156+
var callable = gcHandle.Target;
159157

160158
if (callable is null)
161159
{
@@ -176,13 +174,8 @@ private static unsafe bool IsValid_Native(void* userData)
176174
{
177175
try
178176
{
179-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
180-
var callable = (CustomCallable?)gcHandle.Target;
181-
182-
if (callable is null)
183-
{
184-
return false;
185-
}
177+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
178+
var callable = gcHandle.Target;
186179

187180
return callable.IsValid();
188181
}
@@ -197,12 +190,12 @@ private static unsafe void Free_Native(void* userData)
197190
{
198191
try
199192
{
200-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
193+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
201194
if (gcHandle.Target is IDisposable disposable)
202195
{
203196
disposable.Dispose();
204197
}
205-
gcHandle.Free();
198+
gcHandle.Dispose();
206199
}
207200
catch (Exception exception) when (ExceptionHandling.IsHandled(exception)) { }
208201
}
@@ -212,10 +205,8 @@ private static unsafe uint Hash_Native(void* userData)
212205
{
213206
try
214207
{
215-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
216-
var callable = (CustomCallable?)gcHandle.Target;
217-
218-
Debug.Assert(callable is not null);
208+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
209+
var callable = gcHandle.Target;
219210

220211
return (uint)callable.GetHashCode();
221212
}
@@ -230,11 +221,11 @@ private static unsafe bool Equals_Native(void* userDataLeft, void* userDataRight
230221
{
231222
try
232223
{
233-
var gcHandleLeft = GCHandle.FromIntPtr((nint)userDataLeft);
234-
var callableLeft = (CustomCallable?)gcHandleLeft.Target;
224+
var gcHandleLeft = GCHandle<CustomCallable>.FromIntPtr((nint)userDataLeft);
225+
var callableLeft = gcHandleLeft.Target;
235226

236-
var gcHandleRight = GCHandle.FromIntPtr((nint)userDataRight);
237-
var callableRight = (CustomCallable?)gcHandleRight.Target;
227+
var gcHandleRight = GCHandle<CustomCallable>.FromIntPtr((nint)userDataRight);
228+
var callableRight = gcHandleRight.Target;
238229

239230
return EqualityComparer<CustomCallable>.Default.Equals(callableLeft, callableRight);
240231
}
@@ -249,11 +240,11 @@ private static unsafe bool LessThan_Native(void* userDataLeft, void* userDataRig
249240
{
250241
try
251242
{
252-
var gcHandleLeft = GCHandle.FromIntPtr((nint)userDataLeft);
253-
var callableLeft = (CustomCallable?)gcHandleLeft.Target;
243+
var gcHandleLeft = GCHandle<CustomCallable>.FromIntPtr((nint)userDataLeft);
244+
var callableLeft = gcHandleLeft.Target;
254245

255-
var gcHandleRight = GCHandle.FromIntPtr((nint)userDataRight);
256-
var callableRight = (CustomCallable?)gcHandleRight.Target;
246+
var gcHandleRight = GCHandle<CustomCallable>.FromIntPtr((nint)userDataRight);
247+
var callableRight = gcHandleRight.Target;
257248

258249
return Comparer<CustomCallable>.Default.Compare(callableLeft, callableRight) switch
259250
{
@@ -276,8 +267,8 @@ private static unsafe void ToString_Native(void* userData, bool* outIsValid, Nat
276267
{
277268
try
278269
{
279-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
280-
var callable = (CustomCallable?)gcHandle.Target;
270+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
271+
var callable = gcHandle.Target;
281272

282273
if (callable is null)
283274
{
@@ -302,10 +293,8 @@ private static unsafe long GetArgumentCount_Native(void* userData, bool* outIsVa
302293
{
303294
try
304295
{
305-
var gcHandle = GCHandle.FromIntPtr((nint)userData);
306-
var callable = (CustomCallable?)gcHandle.Target;
307-
308-
Debug.Assert(callable is not null);
296+
var gcHandle = GCHandle<CustomCallable>.FromIntPtr((nint)userData);
297+
var callable = gcHandle.Target;
309298

310299
*outIsValid = callable.TryGetArgumentCount(out long argCount);
311300
return argCount;

src/Godot.Bindings/Bridge/Registration/ClassRegistrationContext.BindMethod.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ partial class ClassRegistrationContext
1111
{
1212
private readonly HashSet<StringName> _registeredMethods = new(StringNameEqualityComparer.Default);
1313

14-
private readonly Dictionary<StringName, GCHandle> _registeredMethodHandles = [];
14+
private readonly Dictionary<StringName, GCHandle<MethodDefinition>> _registeredMethodHandles = [];
1515

1616
// The MethodDefinition must be referenced somewhere so the GC doesn't release it.
1717
// We need to keep it alive because it contains the MethodBindInvoker that
@@ -127,10 +127,10 @@ public unsafe void BindMethod(MethodDefinition methodDefinition)
127127
methodInfoNative.default_arguments = argsDefaultValues;
128128
}
129129

130-
var methodGCHandle = GCHandle.Alloc(methodDefinition, GCHandleType.Normal);
130+
var methodGCHandle = new GCHandle<MethodDefinition>(methodDefinition);
131131
_registeredMethodHandles.Add(methodDefinition.Name, methodGCHandle);
132132

133-
nint methodDefinitionPtr = GCHandle.ToIntPtr(methodGCHandle);
133+
nint methodDefinitionPtr = GCHandle<MethodDefinition>.ToIntPtr(methodGCHandle);
134134
methodInfoNative.call_func = &CallWithVariantArgs_Native;
135135
methodInfoNative.ptrcall_func = &CallWithPtrArgs_Native;
136136
methodInfoNative.method_userdata = (void*)methodDefinitionPtr;
@@ -146,10 +146,8 @@ private static unsafe void CallWithPtrArgs_Native(void* methodUserData, void* in
146146
{
147147
try
148148
{
149-
var gcHandle = GCHandle.FromIntPtr((nint)methodUserData);
150-
var method = (MethodDefinition?)gcHandle.Target;
151-
152-
Debug.Assert(method is not null);
149+
var gcHandle = GCHandle<MethodDefinition>.FromIntPtr((nint)methodUserData);
150+
var method = gcHandle.Target;
153151

154152
method.Invoker.CallWithPtrArgs(method, instance, args, outRet);
155153
}
@@ -161,10 +159,8 @@ private static unsafe void CallWithVariantArgs_Native(void* methodUserData, void
161159
{
162160
try
163161
{
164-
var gcHandle = GCHandle.FromIntPtr((nint)methodUserData);
165-
var method = (MethodDefinition?)gcHandle.Target;
166-
167-
Debug.Assert(method is not null);
162+
var gcHandle = GCHandle<MethodDefinition>.FromIntPtr((nint)methodUserData);
163+
var method = gcHandle.Target;
168164

169165
method.Invoker.CallWithVariantArgs(method, instance, new NativeGodotVariantPtrSpan(args, (int)argCount), outRet, outError);
170166
}

src/Godot.Bindings/Bridge/Registration/ClassRegistrationContext.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public sealed partial class ClassRegistrationContext : IDisposable
1111
{
1212
private bool _disposed;
1313

14-
private GCHandle _gcHandle;
14+
private GCHandle<ClassRegistrationContext> _gcHandle;
1515

16-
internal GCHandle GCHandle => _gcHandle;
16+
internal GCHandle<ClassRegistrationContext> GCHandle => _gcHandle;
1717

1818
internal StringName ClassName { get; }
1919

@@ -23,7 +23,7 @@ public sealed partial class ClassRegistrationContext : IDisposable
2323

2424
internal ClassRegistrationContext(StringName className, StringName nativeClassName)
2525
{
26-
_gcHandle = GCHandle.Alloc(this, GCHandleType.Normal);
26+
_gcHandle = new GCHandle<ClassRegistrationContext>(this);
2727
ClassName = className;
2828
NativeClassName = nativeClassName;
2929
}
@@ -50,10 +50,10 @@ public void Dispose()
5050

5151
foreach (var handle in _registeredMethodHandles.Values)
5252
{
53-
handle.Free();
53+
handle.Dispose();
5454
}
5555
_registeredMethodHandles.Clear();
5656

57-
_gcHandle.Free();
57+
_gcHandle.Dispose();
5858
}
5959
}

0 commit comments

Comments
 (0)