Skip to content

Commit 75de7f3

Browse files
rolfbjarneCopilot
andauthored
[Foundation] Improve nullability in NSArray.ArrayFromHandleFunc. (#24900)
* Improve nullability annotations for ArrayFromHandleFunc<T> (return T?[]?). * Add an ArrayFromHandleDropNullElements overload with Converter and NSNullBehavior parameters. * Update DictionaryContainer.GetArray and GetArrayOfDictionariesValue to use ArrayFromHandleDropNullElements. * Update NSUrlSessionConfiguration.ProxyConfigurations to use NonNullArrayFromHandleDropNullElements. * Update PdfAnnotation.QuadrilateralPoints to return CGPoint[]? and use ArrayFromHandle. * Update XML docs for ArrayFromHandleFunc, ProxyConfigurations and QuadrilateralPoints. Contributes towards #17285. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5390722 commit 75de7f3

5 files changed

Lines changed: 47 additions & 41 deletions

File tree

src/Foundation/DictionaryContainer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ bool TryGetNativeValue (NativeHandle key, out NativeHandle value)
215215
if (!TryGetNativeValue (key, out var value))
216216
return null;
217217

218-
return NSArray.ArrayFromHandleFunc<T> (value, creator);
218+
return NSArray.ArrayFromHandleDropNullElements<T> (value, (v) => creator (v), NSNullBehavior.DropIfIncompatible);
219219
}
220220

221221
/// <summary>Retrieves the <see cref="DictionaryContainer" /> array associeted with <paramref name="key" />.</summary>
@@ -226,7 +226,7 @@ bool TryGetNativeValue (NativeHandle key, out NativeHandle value)
226226
if (!TryGetNativeValue (key, out var value))
227227
return null;
228228

229-
return NSArray.ArrayFromHandleFunc<T> (value, (handle) => Create<T> (handle)!);
229+
return NSArray.ArrayFromHandleDropNullElements<T> (value, (handle) => Create<T> (handle)!, NSNullBehavior.DropIfIncompatible);
230230
}
231231

232232
/// <summary>Returns the nullable <see cref="byte" /> associated with the specified <paramref name="key" />.</summary>

src/Foundation/NSArray.cs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,18 @@ static bool TryGetItem<T> (NativeHandle elementHandle, Converter<NativeHandle, T
686686
return ArrayFromHandle<T> (handle, (h) => Runtime.GetINativeObject<T> (h, false)!, nsNullElementBehavior, releaseHandle)!;
687687
}
688688

689+
/// <summary>Returns a strongly-typed C# array from a handle to an NSArray, dropping null elements.</summary>
690+
/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
691+
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
692+
/// <param name="createObject">A delegate to convert a native handle to an object of type T.</param>
693+
/// <param name="nsNullElementBehavior">How to handle null and NSNull elements in the native array.</param>
694+
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not.</param>
695+
/// <returns>A C# array with the values (excluding null elements). Returns <see langword="null" /> if the handle is <see cref="NativeHandle.Zero" />.</returns>
696+
internal static T []? ArrayFromHandleDropNullElements<T> (NativeHandle handle, Converter<NativeHandle, T> createObject, NSNullBehavior nsNullElementBehavior, bool releaseHandle = false)
697+
{
698+
return ArrayFromHandle<T> (handle, createObject, nsNullElementBehavior, releaseHandle)!;
699+
}
700+
689701
/// <summary>Returns a strongly-typed C# array from a handle to an NSArray, dropping null elements and guaranteeing a non-null return value.</summary>
690702
/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
691703
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
@@ -832,36 +844,38 @@ internal static T [] ToNonNullArrayDropNullElements<T> (NSArray? weakArray) wher
832844
}
833845
}
834846

835-
#nullable disable
836-
// Used when we need to provide our constructor
837-
/// <typeparam name="T">Parameter type, determines the kind of array returned.</typeparam>
838-
/// <param name="handle">Pointer (handle) to the unmanaged object.</param>
839-
/// <param name="createObject">To be added.</param>
840-
/// <summary>Returns a strongly-typed C# array of the parametrized type from a handle to an NSArray.</summary>
841-
/// <returns>An C# array with the values.</returns>
847+
/// <summary>Creates a strongly-typed C# array from a handle to an <see cref="NSArray" />, using a custom factory function.</summary>
848+
/// <typeparam name="T">The element type for the returned array.</typeparam>
849+
/// <param name="handle">Pointer (handle) to the unmanaged <see cref="NSArray" /> object.</param>
850+
/// <param name="createObject">A factory function that creates an instance of <typeparamref name="T" /> from a native handle.</param>
851+
/// <returns>A C# array with the values, or <see langword="null" /> if <paramref name="handle" /> is <see cref="NativeHandle.Zero" />.</returns>
842852
/// <remarks>
843-
/// <para>Use this method to get a set of NSObject arrays from a handle to an NSArray. Instead of wrapping the results in NSObjects, the code invokes your method to create the return value.</para>
844-
/// <example>
845-
/// <code lang="c#"><![CDATA[
846-
/// int [] args = NSArray.ArrayFromHandle<int> (someHandle, (x) => (int) x);
853+
/// <para>
854+
/// Instead of wrapping the results in <see cref="NSObject" /> instances,
855+
/// this method invokes <paramref name="createObject" /> for each element to create the return value.
856+
/// </para>
857+
/// <example>
858+
/// <code lang="c#"><![CDATA[
859+
/// var args = NSArray.ArrayFromHandleFunc<int> (someHandle, (x) => (int) x);
847860
/// ]]></code>
848-
/// </example>
849-
/// </remarks>
850-
static public T [] ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandle, T> createObject)
861+
/// </example>
862+
/// </remarks>
863+
public static T? []? ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandle, T> createObject)
851864
{
852865
return ArrayFromHandle<T> (handle, (v) => createObject (v));
853866
}
854867

855-
/// <summary>Create a managed array from a pointer to a native NSArray instance.</summary>
856-
/// <param name="handle">The pointer to the native NSArray instance.</param>
857-
/// <param name="createObject">A callback that returns an instance of the type T for a given pointer (for an element in the NSArray).</param>
858-
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not.</param>
859-
public static T [] ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandle, T> createObject, bool releaseHandle)
868+
/// <summary>Creates a strongly-typed C# array from a handle to an <see cref="NSArray" />, using a custom factory function.</summary>
869+
/// <typeparam name="T">The element type for the returned array.</typeparam>
870+
/// <param name="handle">Pointer (handle) to the unmanaged <see cref="NSArray" /> object.</param>
871+
/// <param name="createObject">A factory function that creates an instance of <typeparamref name="T" /> from a native handle.</param>
872+
/// <param name="releaseHandle">Whether the native <see cref="NSArray" /> instance should be released before returning or not.</param>
873+
/// <returns>A C# array with the values, or <see langword="null" /> if <paramref name="handle" /> is <see cref="NativeHandle.Zero" />.</returns>
874+
public static T? []? ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandle, T> createObject, bool releaseHandle)
860875
{
861876
return ArrayFromHandle<T> (handle, (v) => createObject (v), releaseHandle);
862877
}
863878

864-
#nullable enable
865879
/// <summary>Creates a managed array from a pointer to a native NSArray of NSDictionary objects, dropping null and NSNull elements.</summary>
866880
/// <typeparam name="T">The type of objects to create from the dictionaries.</typeparam>
867881
/// <param name="handle">The pointer to the native NSArray instance containing NSDictionary objects.</param>

src/Foundation/NSUrlSessionConfiguration.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,17 @@ public static NSUrlSessionConfiguration CreateBackgroundSessionConfiguration (st
7070
return config;
7171
}
7272

73+
/// <summary>Gets or sets the proxy configurations for this session.</summary>
74+
/// <value>An array of <see cref="Network.NWProxyConfig" /> objects representing the proxy configurations.</value>
7375
[SupportedOSPlatform ("ios17.0")]
7476
[SupportedOSPlatform ("macos14.0")]
7577
[SupportedOSPlatform ("maccatalyst17.0")]
7678
[SupportedOSPlatform ("tvos17.0")]
7779
public NWProxyConfig [] ProxyConfigurations {
78-
get => NSArray.ArrayFromHandleFunc (_ProxyConfigurations, handle => new NWProxyConfig (handle, owns: false));
80+
get => NSArray.NonNullArrayFromHandleDropNullElements (_ProxyConfigurations, handle => new NWProxyConfig (handle, owns: false));
7981
set {
80-
var arr = NSArray.FromNSObjects (value);
81-
_ProxyConfigurations = arr.Handle;
82-
GC.KeepAlive (arr);
82+
using var arr = NSArray.FromNSObjects (value);
83+
_ProxyConfigurations = arr.GetHandle ();
8384
}
8485
}
8586

src/PdfKit/PdfAnnotation.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,30 +76,22 @@ public PdfAnnotationKey AnnotationType {
7676
set { Type = value.GetConstant ()!; }
7777
}
7878

79-
/// <summary>To be added.</summary>
80-
/// <value>To be added.</value>
81-
/// <remarks>To be added.</remarks>
79+
/// <summary>Gets or sets the points defining the quadrilateral bounds of the annotation.</summary>
80+
/// <value>An array of <see cref="CGPoint" /> values representing the quadrilateral vertices, or <see langword="null" />.</value>
8281
[SupportedOSPlatform ("macos")]
8382
[SupportedOSPlatform ("ios")]
8483
[SupportedOSPlatform ("maccatalyst")]
8584
[SupportedOSPlatform ("tvos18.2")]
86-
public CGPoint [] QuadrilateralPoints {
85+
public CGPoint []? QuadrilateralPoints {
8786
get {
88-
return NSArray.ArrayFromHandleFunc<CGPoint> (_QuadrilateralPoints, (v) => {
87+
return NSArray.ArrayFromHandle<CGPoint> (_QuadrilateralPoints, (v) => {
8988
using (var value = new NSValue (v))
9089
return value.CGPointValue;
9190
});
9291
}
9392
set {
94-
if (value is null) {
95-
_QuadrilateralPoints = IntPtr.Zero;
96-
} else {
97-
using (var arr = new NSMutableArray ()) {
98-
for (int i = 0; i < value.Length; i++)
99-
arr.Add (NSValue.FromCGPoint (value [i]));
100-
_QuadrilateralPoints = arr.Handle;
101-
}
102-
}
93+
using var arr = NSArray.FromNSObjects<CGPoint> ((element) => NSValue.FromCGPoint (element), value);
94+
_QuadrilateralPoints = arr.GetHandle ();
10395
}
10496
}
10597
}

tests/cecil-tests/Documentation.KnownFailures.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21062,7 +21062,6 @@ P:Foundation.NSUbiquitousKeyValueStoreChangeEventArgs.ChangedKeys
2106221062
P:Foundation.NSUbiquitousKeyValueStoreChangeEventArgs.ChangeReason
2106321063
P:Foundation.NSUndoManagerCloseUndoGroupEventArgs.Discardable
2106421064
P:Foundation.NSUrlAuthenticationChallenge.SenderObject
21065-
P:Foundation.NSUrlSessionConfiguration.ProxyConfigurations
2106621065
P:Foundation.NSUrlSessionConfiguration.SessionType
2106721066
P:Foundation.NSUrlSessionConfiguration.StrongConnectionProxyDictionary
2106821067
P:Foundation.NSUrlSessionHandler.AllowsCellularAccess

0 commit comments

Comments
 (0)