Skip to content
Open
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
75 changes: 42 additions & 33 deletions src/Foundation/NSDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,37 @@ internal static NSArray PickOdd (object f, object [] args)
return NSArray.FromObjects (ret);
}

// Checks:
// * 'objects' and 'keys' for null
// * count isn't negative
// * count isn't higher than the number of elements in either array
// returns false if an empty dictionary can be returned
private protected static bool ValidateFromObjectsAndKeys<T, K> (T [] objects, K [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (count < 0 || objects.Length < count || keys.Length < count)
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent exception type for negative count. This validation throws ArgumentException for negative count values, but ArgumentOutOfRangeException would be more appropriate and consistent with NSArray.FromNativeObjects which throws ArgumentOutOfRangeException for negative count (NSArray.cs line 238-239). Consider changing the exception type when count is negative to ArgumentOutOfRangeException, while keeping ArgumentException for other validation failures.

Suggested change
if (count < 0 || objects.Length < count || keys.Length < count)
if (count < 0)
throw new ArgumentOutOfRangeException (nameof (count));
if (objects.Length < count || keys.Length < count)

Copilot uses AI. Check for mistakes.
throw new ArgumentException (nameof (count));
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message for the count validation is too generic. When count is negative or too large, the exception message only contains the parameter name "count" without explaining what's wrong. Consider providing a more descriptive error message such as "count must be non-negative and not greater than the length of both arrays" to help developers understand the issue.

Suggested change
throw new ArgumentException (nameof (count));
throw new ArgumentException ("count must be non-negative and not greater than the length of both arrays", nameof (count));

Copilot uses AI. Check for mistakes.

return count > 0;
}

// Checks:
// * 'objects' and 'keys' for null
// * 'objects' and 'keys' have the same number of elements
// returns false if an empty dictionary can be returned
private protected static bool ValidateFromObjectsAndKeys<T, K> (T [] objects, K [] keys)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");

return objects.Length > 0;
}

/// <summary>
/// Creates a dictionary from a set of values and keys.
/// </summary>
Expand All @@ -137,12 +168,8 @@ internal static NSArray PickOdd (object f, object [] args)
/// <returns>A new <see cref="NSDictionary"/> containing the specified key-value pairs.</returns>
public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSDictionary ();

return FromObjectsAndKeys (objects, keys, keys.Length);
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent use of array length in forwarding calls. This method uses keys.Length when forwarding to the count-based overload, while most other similar methods use objects.Length (e.g., NSMutableDictionary.cs lines 47, 61; NSDictionary_2.cs line 292; NSMutableDictionary_2.cs lines 287, 301). Since validation ensures both arrays have the same length, this doesn't affect functionality, but for maintainability and consistency, all forwarding calls should use the same pattern. Consider using objects.Length consistently across all implementations.

Suggested change
return FromObjectsAndKeys (objects, keys, keys.Length);
return FromObjectsAndKeys (objects, keys, objects.Length);

Copilot uses AI. Check for mistakes.
}
Expand All @@ -160,35 +187,23 @@ public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject []
/// </remarks>
public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSDictionary ();

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
return FromObjectsAndKeysInternal (no, nk);
return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>
/// Creates a dictionary from a set of values and keys.
/// </summary>
/// <param name="objects">Array of values for the dictionary. Null elements are stored as <see cref="NSNull.Null"/>.</param>
/// <param name="keys">Array of keys for the dictionary.</param>
/// <param name="count">Number of items to use in the creation; the number must be less than or equal to the number of elements in the arrays.</param>
/// <param name="count">Number of items to use in the creation; the number must be less than or equal to the number of elements in both arrays.</param>
/// <returns>A new <see cref="NSDictionary"/> containing the specified key-value pairs.</returns>
public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys, nint count)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException ("count");
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSDictionary ();

using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
Expand All @@ -200,7 +215,7 @@ public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject []
/// </summary>
/// <param name="objects">Array of values for the dictionary.</param>
/// <param name="keys">Array of keys for the dictionary.</param>
/// <param name="count">Number of items to use in the creation; the number must be less than or equal to the number of elements in the arrays.</param>
/// <param name="count">Number of items to use in the creation; the number must be less than or equal to the number of elements in both arrays.</param>
/// <returns>A new <see cref="NSDictionary"/> containing the specified key-value pairs.</returns>
/// <remarks>
/// <para>
Expand All @@ -209,14 +224,8 @@ public static NSDictionary FromObjectsAndKeys (NSObject? [] objects, NSObject []
/// </remarks>
public static NSDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException ("count");
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSDictionary ();

using (var no = NSArray.FromObjects (count, objects))
using (var nk = NSArray.FromObjects (count, keys))
Expand Down
45 changes: 11 additions & 34 deletions src/Foundation/NSDictionary_2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,8 @@ static NSDictionary<TKey, TValue> GenericFromObjectsAndKeysInternal (NSArray obj
/// <returns>A new dictionary containing the specified key-value pairs.</returns>
public static NSDictionary<TKey, TValue> FromObjectsAndKeys (TValue? [] objects, TKey [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSDictionary<TKey, TValue> ();

using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
Expand All @@ -277,11 +272,8 @@ public static NSDictionary<TKey, TValue> FromObjectsAndKeys (TValue? [] objects,
/// <returns>A new dictionary containing the specified key-value pairs.</returns>
public static NSDictionary<TKey, TValue> FromObjectsAndKeys (TValue? [] objects, TKey [] keys)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSDictionary<TKey, TValue> ();

return FromObjectsAndKeys (objects, keys, keys.Length);
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent use of array length in forwarding calls. This method uses keys.Length when forwarding to the count-based overload, while most other similar methods use objects.Length (e.g., NSMutableDictionary.cs lines 47, 61; NSDictionary_2.cs line 292; NSMutableDictionary_2.cs lines 287, 301). Since validation ensures both arrays have the same length, this doesn't affect functionality, but for maintainability and consistency, all forwarding calls should use the same pattern. Consider using objects.Length consistently across all implementations.

Suggested change
return FromObjectsAndKeys (objects, keys, keys.Length);
return FromObjectsAndKeys (objects, keys, objects.Length);

Copilot uses AI. Check for mistakes.
}
Expand All @@ -294,15 +286,10 @@ public static NSDictionary<TKey, TValue> FromObjectsAndKeys (TValue? [] objects,
/// <returns>A new dictionary containing the specified key-value pairs.</returns>
public static NSDictionary<TKey, TValue> FromObjectsAndKeys (object [] objects, object [] keys)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSDictionary<TKey, TValue> ();

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
return GenericFromObjectsAndKeysInternal (no, nk);
return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>
Expand All @@ -314,13 +301,8 @@ public static NSDictionary<TKey, TValue> FromObjectsAndKeys (object [] objects,
/// <returns>A new dictionary containing the specified key-value pairs.</returns>
public static NSDictionary<TKey, TValue> FromObjectsAndKeys (NSObject? [] objects, NSObject [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSDictionary<TKey, TValue> ();

using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
Expand All @@ -336,13 +318,8 @@ public static NSDictionary<TKey, TValue> FromObjectsAndKeys (NSObject? [] object
/// <returns>A new dictionary containing the specified key-value pairs.</returns>
public static NSDictionary<TKey, TValue> FromObjectsAndKeys (object [] objects, object [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);

if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSDictionary<TKey, TValue> ();

using (var no = NSArray.FromObjects (count, objects))
using (var nk = NSArray.FromObjects (count, keys))
Expand Down
64 changes: 20 additions & 44 deletions src/Foundation/NSMutableDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,10 @@ public partial class NSMutableDictionary : NSDictionary, IDictionary, IDictionar
/// <exception cref="ArgumentException">Thrown when the arrays have different sizes.</exception>
public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");

using (var no = NSArray.FromNSObjects (objects))
using (var nk = NSArray.FromNSObjects (keys))
return FromObjectsAndKeysInternal (no, nk);
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSMutableDictionary ();

return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>Creates a mutable dictionary from the specified arrays of objects and keys.</summary>
Expand All @@ -61,16 +55,10 @@ public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObj
/// <exception cref="ArgumentException">Thrown when the arrays have different sizes.</exception>
public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
return FromObjectsAndKeysInternal (no, nk);
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSMutableDictionary ();

return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>Creates a mutable dictionary from the specified number of objects and keys from the arrays.</summary>
Expand All @@ -79,20 +67,14 @@ public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object
/// <param name="count">The number of elements to copy from the arrays.</param>
/// <returns>A new mutable dictionary containing the specified objects and keys.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="objects"/> or <paramref name="keys"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">Thrown when the arrays have different sizes or <paramref name="count"/> is invalid.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="count"/> is invalid.</exception>
public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));

using (var no = NSArray.FromNSObjects (objects))
using (var nk = NSArray.FromNSObjects (keys))
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSMutableDictionary ();

using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
return FromObjectsAndKeysInternal (no, nk);
}

Expand All @@ -102,20 +84,14 @@ public static NSMutableDictionary FromObjectsAndKeys (NSObject [] objects, NSObj
/// <param name="count">The number of elements to copy from the arrays.</param>
/// <returns>A new mutable dictionary containing the specified objects and keys.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="objects"/> or <paramref name="keys"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">Thrown when the arrays have different sizes or <paramref name="count"/> is invalid.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="count"/> is invalid.</exception>
public static NSMutableDictionary FromObjectsAndKeys (object [] objects, object [] keys, nint count)
{
if (objects is null)
throw new ArgumentNullException (nameof (objects));
if (keys is null)
throw new ArgumentNullException (nameof (keys));
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSMutableDictionary ();

using (var no = NSArray.FromObjects (count, objects))
using (var nk = NSArray.FromObjects (count, keys))
return FromObjectsAndKeysInternal (no, nk);
}

Expand Down
56 changes: 18 additions & 38 deletions src/Foundation/NSMutableDictionary_2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,11 @@ public TValue? this [TKey index] {
/// <returns>A new mutable dictionary containing the specified key-value pairs.</returns>
public static NSMutableDictionary<TKey, TValue>? FromObjectsAndKeys (TValue [] objects, TKey [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSMutableDictionary<TKey, TValue> ();

using (var no = NSArray.FromNSObjects (objects))
using (var nk = NSArray.FromNSObjects (keys))
using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
return GenericFromObjectsAndKeysInternal (no, nk);
}

Expand All @@ -285,14 +281,10 @@ public TValue? this [TKey index] {
/// <returns>A new mutable dictionary containing the specified key-value pairs.</returns>
public static NSMutableDictionary<TKey, TValue>? FromObjectsAndKeys (TValue [] objects, TKey [] keys)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSMutableDictionary<TKey, TValue> ();

using (var no = NSArray.FromNSObjects (objects))
using (var nk = NSArray.FromNSObjects (keys))
return GenericFromObjectsAndKeysInternal (no, nk);
return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>
Expand All @@ -303,14 +295,10 @@ public TValue? this [TKey index] {
/// <returns>A new mutable dictionary containing the specified key-value pairs.</returns>
public static NSMutableDictionary<TKey, TValue>? FromObjectsAndKeys (object [] objects, object [] keys)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (!ValidateFromObjectsAndKeys (objects, keys))
return new NSMutableDictionary<TKey, TValue> ();

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
return GenericFromObjectsAndKeysInternal (no, nk);
return FromObjectsAndKeys (objects, keys, objects.Length);
}

/// <summary>
Expand All @@ -322,15 +310,11 @@ public TValue? this [TKey index] {
/// <returns>A new mutable dictionary containing the specified key-value pairs.</returns>
public static NSMutableDictionary<TKey, TValue>? FromObjectsAndKeys (NSObject [] objects, NSObject [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSMutableDictionary<TKey, TValue> ();

using (var no = NSArray.FromNSObjects (objects))
using (var nk = NSArray.FromNSObjects (keys))
using (var no = NSArray.FromNativeObjects (objects, count))
using (var nk = NSArray.FromNativeObjects (keys, count))
return GenericFromObjectsAndKeysInternal (no, nk);
}

Expand All @@ -343,15 +327,11 @@ public TValue? this [TKey index] {
/// <returns>A new mutable dictionary containing the specified key-value pairs.</returns>
public static NSMutableDictionary<TKey, TValue>? FromObjectsAndKeys (object [] objects, object [] keys, nint count)
{
ArgumentNullException.ThrowIfNull (objects);
ArgumentNullException.ThrowIfNull (keys);
if (objects.Length != keys.Length)
throw new ArgumentException (nameof (objects) + " and " + nameof (keys) + " arrays have different sizes");
if (count < 1 || objects.Length < count || keys.Length < count)
throw new ArgumentException (nameof (count));
if (!ValidateFromObjectsAndKeys (objects, keys, count))
return new NSMutableDictionary<TKey, TValue> ();

using (var no = NSArray.FromObjects (objects))
using (var nk = NSArray.FromObjects (keys))
using (var no = NSArray.FromObjects (count, objects))
using (var nk = NSArray.FromObjects (count, keys))
return GenericFromObjectsAndKeysInternal (no, nk);
}

Expand Down
Loading
Loading