Skip to content

Commit 04448f4

Browse files
rolfbjarneCopilot
andauthored
[Foundation] Improve nullability in NSArray.FromArrayOfArray. (#24919)
* Improve nullability annotations for FromArrayOfArray (accept NSArray?, return NSObject[][]?). * Rewrite FromArrayOfArray to use ArrayFromHandleDropNullElements. * Improve nullability annotations for From(NSObject[][]) (accept NSObject[][]?, return NSArray?). * Rewrite From(NSObject[][]) to use FromNSObjects. * Update XML docs for all modified members. * Add tests for NSArray.FromArrayOfArray, NSArray.From(NSObject[][]) and NSEntityDescription.UniquenessConstraints. Contributes towards #17285. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4077c4b commit 04448f4

4 files changed

Lines changed: 133 additions & 32 deletions

File tree

src/CoreData/NSEntityDescription.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@
1010

1111
namespace CoreData {
1212
/// <summary>Describes the value relationships between an in-memory object and its persistent representation.</summary>
13-
/// <remarks>To be added.</remarks>
1413
/// <related type="externalDocumentation" href="https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSEntityDescription_Class/index.html">Apple documentation for <c>NSEntityDescription</c></related>
1514
public partial class NSEntityDescription {
1615
/// <summary>Gets or sets the uniqueness constraints for this entity.</summary>
17-
/// <value>To be added.</value>
18-
/// <remarks>To be added.</remarks>
16+
/// <value>
17+
/// A jagged array where each element is an array of <see cref="NSObject" /> properties
18+
/// that together form a uniqueness constraint. The returned array is never <see langword="null" />; it will be an empty array if no uniqueness constraints are configured.
19+
/// </value>
1920
[SupportedOSPlatform ("ios")]
2021
[SupportedOSPlatform ("macos")]
2122
[SupportedOSPlatform ("maccatalyst")]
2223
[SupportedOSPlatform ("tvos")]
2324
public NSObject [] [] UniquenessConstraints {
24-
get { return NSArray.FromArrayOfArray (_UniquenessConstraints); }
25-
set { _UniquenessConstraints = NSArray.From (value); }
25+
get { return NSArray.FromArrayOfArray (_UniquenessConstraints)!; }
26+
set { _UniquenessConstraints = NSArray.From (value)!; }
2627
}
2728
}
2829
}

src/Foundation/NSArray.cs

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -947,47 +947,35 @@ internal static T [] NonNullDictionaryArrayFromHandleDropNullElements<T> (Native
947947
return UnsafeGetItem<T> (Handle, index);
948948
}
949949

950-
#nullable disable
951-
/// <param name="weakArray">To be added.</param>
952-
/// <summary>To be added.</summary>
953-
/// <returns>To be added.</returns>
954-
/// <remarks>To be added.</remarks>
955-
public static NSObject [] [] FromArrayOfArray (NSArray weakArray)
950+
/// <summary>Creates a jagged array of <see cref="NSObject" /> arrays from an <see cref="NSArray" /> of <see cref="NSArray" /> objects.</summary>
951+
/// <param name="weakArray">An <see cref="NSArray" /> containing nested <see cref="NSArray" /> elements, or <see langword="null" />.</param>
952+
/// <returns>A jagged array of <see cref="NSObject" /> arrays, or <see langword="null" /> if <paramref name="weakArray" /> is <see langword="null" /> or a conversion error occurs.</returns>
953+
public static NSObject [] []? FromArrayOfArray (NSArray? weakArray)
956954
{
957-
if (weakArray is null || weakArray.Handle == IntPtr.Zero)
958-
return null;
959-
960955
try {
961-
nuint n = weakArray.Count;
962-
var ret = new NSObject [n] [];
963-
for (nuint i = 0; i < n; i++)
964-
ret [i] = NSArray.FromArray<NSObject> (weakArray.GetItem<NSArray> (i));
965-
return ret;
956+
var rv = ArrayFromHandleDropNullElements<NSObject []> (
957+
weakArray.GetHandle (),
958+
(v) => NonNullArrayFromHandleDropNullElements<NSObject> (v),
959+
NSNullBehavior.DropIfIncompatible);
960+
GC.KeepAlive (weakArray);
961+
return rv;
966962
} catch {
967963
return null;
968964
}
969965
}
970966

971-
/// <param name="items">To be added.</param>
972-
/// <summary>To be added.</summary>
973-
/// <returns>To be added.</returns>
974-
/// <remarks>To be added.</remarks>
975-
public static NSArray From (NSObject [] [] items)
967+
/// <summary>Creates an <see cref="NSArray" /> from a jagged array of <see cref="NSObject" /> arrays.</summary>
968+
/// <param name="items">A jagged array of <see cref="NSObject" /> arrays to convert, or <see langword="null" />.</param>
969+
/// <returns>An <see cref="NSArray" /> containing nested <see cref="NSArray" /> elements, or <see langword="null" /> if <paramref name="items" /> is <see langword="null" /> or a conversion error occurs.</returns>
970+
public static NSArray? From (NSObject [] []? items)
976971
{
977-
if (items is null)
978-
return null;
979-
980972
try {
981-
var ret = new NSMutableArray ((nuint) items.Length);
982-
for (int i = 0; i < items.Length; i++)
983-
ret.Add (NSArray.FromNSObjects (items [i]));
984-
return ret;
973+
return FromNSObjects ((item) => NSArray.FromNSObjects (item), items);
985974
} catch {
986975
return null;
987976
}
988977
}
989978

990-
#nullable enable
991979
/// <summary>Converts this <see cref="NSArray" /> to a strongly-typed C# array, dropping null and incompatible elements.</summary>
992980
/// <typeparam name="T">The element type for the returned array. Must be a class that implements <see cref="INativeObject" />.</typeparam>
993981
/// <returns>A C# array of <typeparamref name="T" /> elements, excluding any null or incompatible elements.</returns>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using CoreData;
5+
6+
namespace MonoTouchFixtures.CoreData {
7+
8+
[TestFixture]
9+
[Preserve (AllMembers = true)]
10+
public class EntityDescriptionTest {
11+
12+
[Test]
13+
public void UniquenessConstraints ()
14+
{
15+
using var entity = new NSEntityDescription ();
16+
17+
// Default is an empty array, not null
18+
var defaultValue = entity.UniquenessConstraints;
19+
Assert.IsNotNull (defaultValue, "default not null");
20+
Assert.AreEqual (0, defaultValue!.Length, "default empty");
21+
22+
// Add attributes so the entity knows about these property names
23+
using var nameAttr = new NSAttributeDescription { Name = "name", AttributeType = NSAttributeType.String };
24+
using var emailAttr = new NSAttributeDescription { Name = "email", AttributeType = NSAttributeType.String };
25+
using var idAttr = new NSAttributeDescription { Name = "id", AttributeType = NSAttributeType.String };
26+
entity.Properties = new NSPropertyDescription [] { nameAttr, emailAttr, idAttr };
27+
28+
var constraints = new NSObject [] [] {
29+
new NSObject [] { (NSString) "name", (NSString) "email" },
30+
new NSObject [] { (NSString) "id" },
31+
};
32+
entity.UniquenessConstraints = constraints;
33+
34+
var result = entity.UniquenessConstraints;
35+
Assert.IsNotNull (result, "result");
36+
Assert.AreEqual (2, result!.Length, "outer length");
37+
Assert.AreEqual (2, result [0].Length, "constraint0 length");
38+
Assert.AreEqual (1, result [1].Length, "constraint1 length");
39+
}
40+
}
41+
}

tests/monotouch-test/Foundation/NSArray1Test.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,5 +488,76 @@ public void GetDifferenceFromArrayTest ()
488488
Assert.NotNull (diff, "Not null");
489489
}
490490
#endif
491+
492+
[Test]
493+
public void FromArrayOfArray ()
494+
{
495+
var inner1 = NSArray.FromNSObjects ((NSString) "a", (NSString) "b");
496+
var inner2 = NSArray.FromNSObjects ((NSString) "c");
497+
using var outer = NSArray.FromNSObjects (inner1, inner2);
498+
499+
var result = NSArray.FromArrayOfArray (outer);
500+
501+
Assert.IsNotNull (result, "result");
502+
Assert.AreEqual (2, result!.Length, "outer length");
503+
Assert.AreEqual (2, result [0].Length, "inner1 length");
504+
Assert.AreEqual (1, result [1].Length, "inner2 length");
505+
Assert.AreEqual ("a", result [0] [0].ToString (), "inner1[0]");
506+
Assert.AreEqual ("b", result [0] [1].ToString (), "inner1[1]");
507+
Assert.AreEqual ("c", result [1] [0].ToString (), "inner2[0]");
508+
}
509+
510+
[Test]
511+
public void FromArrayOfArray_Null ()
512+
{
513+
var result = NSArray.FromArrayOfArray (null);
514+
Assert.IsNull (result, "result");
515+
}
516+
517+
[Test]
518+
public void From_JaggedArray ()
519+
{
520+
var items = new NSObject [] [] {
521+
new NSObject [] { (NSString) "x", (NSString) "y" },
522+
new NSObject [] { (NSString) "z" },
523+
};
524+
525+
using var arr = NSArray.From (items);
526+
527+
Assert.IsNotNull (arr, "arr");
528+
Assert.AreEqual ((nuint) 2, arr!.Count, "outer count");
529+
var row0 = arr.GetItem<NSArray> (0)!;
530+
var row1 = arr.GetItem<NSArray> (1)!;
531+
Assert.AreEqual ((nuint) 2, row0.Count, "row0 count");
532+
Assert.AreEqual ((nuint) 1, row1.Count, "row1 count");
533+
}
534+
535+
[Test]
536+
public void From_JaggedArray_Null ()
537+
{
538+
var result = NSArray.From ((NSObject [] []?) null);
539+
Assert.IsNull (result, "result");
540+
}
541+
542+
[Test]
543+
public void FromArrayOfArray_Roundtrip ()
544+
{
545+
var original = new NSObject [] [] {
546+
new NSObject [] { (NSString) "1", (NSString) "2" },
547+
new NSObject [] { (NSString) "3" },
548+
};
549+
550+
using var native = NSArray.From (original);
551+
Assert.IsNotNull (native, "native");
552+
553+
var roundtripped = NSArray.FromArrayOfArray (native);
554+
Assert.IsNotNull (roundtripped, "roundtripped");
555+
Assert.AreEqual (original.Length, roundtripped!.Length, "outer length");
556+
Assert.AreEqual (original [0].Length, roundtripped [0].Length, "inner0 length");
557+
Assert.AreEqual (original [1].Length, roundtripped [1].Length, "inner1 length");
558+
Assert.AreEqual ("1", roundtripped [0] [0].ToString (), "[0][0]");
559+
Assert.AreEqual ("2", roundtripped [0] [1].ToString (), "[0][1]");
560+
Assert.AreEqual ("3", roundtripped [1] [0].ToString (), "[1][0]");
561+
}
491562
}
492563
}

0 commit comments

Comments
 (0)