Skip to content

Commit 05c9830

Browse files
rolfbjarneGitHub CopilotCopilot
authored
[Foundation] Fix nullability in NSMutableDictionary. (#24428)
* Enable nullability for NSMutableDictionary.cs. * Fix interface implementations to match nullability contracts (IDictionary, IDictionary<NSObject, NSObject>). * Make indexers' return type allow null, but disallow setting null values. * Remove all 'To be added.' XML comments. * Add comprehensive XML documentation for all public methods, properties, and indexers. * Use proper 'see cref' attributes for type references in documentation. * Fix ArgumentNullException to use nameof for parameter names. * Remove an unused constructor. Also add NSMutableDictionary tests for missing key behavior: * Add tests to verify that accessing missing keys returns null. * Test all indexer overloads (string, NSObject, NSString). * Test ObjectForKey method with missing keys. * Test TryGetValue with missing keys returns false and null output. * Test IDictionary interface implementations (indexer and Contains). * Ensure existing keys still work correctly after testing missing keys. These tests document and verify the expected behavior when fetching values for keys that don't exist in the dictionary. This is file 34 of 47 files with nullability disabled in Foundation. Contributes towards #17285. --------- Co-authored-by: GitHub Copilot <copilot@github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 2a471e5 commit 05c9830

File tree

14 files changed

+843
-154
lines changed

14 files changed

+843
-154
lines changed

src/AudioToolbox/AudioFile.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,10 +2376,11 @@ public unsafe byte []? ID3Tag {
23762376
public AudioFileInfoDictionary? InfoDictionary {
23772377
get {
23782378
var ptr = GetIntPtr (AudioFileProperty.InfoDictionary);
2379-
if (ptr == IntPtr.Zero)
2379+
var dict = Runtime.GetNSObject<NSMutableDictionary> (ptr, owns: true);
2380+
if (dict is null)
23802381
return null;
23812382

2382-
return new AudioFileInfoDictionary (new NSMutableDictionary (ptr, true));
2383+
return new AudioFileInfoDictionary (dict);
23832384
}
23842385
}
23852386

src/AudioToolbox/AudioToolbox.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ internal InstrumentInfo (NSDictionary d)
3939
/// <summary>To be added.</summary>
4040
/// <value>To be added.</value>
4141
/// <remarks>To be added.</remarks>
42-
public string Name {
43-
get { return Dictionary [NameKey].ToString (); }
42+
public string? Name {
43+
get { return Dictionary [NameKey]?.ToString (); }
4444
}
4545

4646
/// <summary>To be added.</summary>

src/CoreText/CTFont.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,10 @@ public string? Name {
429429
/// <remarks>To be added.</remarks>
430430
public FontFeatureGroup FeatureGroup {
431431
get {
432-
return (FontFeatureGroup) (int) (NSNumber) Dictionary [CTFontFeatureKey.Identifier];
432+
var number = (NSNumber?) Dictionary [CTFontFeatureKey.Identifier];
433+
if (number is null)
434+
return default;
435+
return (FontFeatureGroup) (int) number;
433436
}
434437
}
435438

@@ -591,7 +594,10 @@ internal static CTFontFeatureSelectors Create (FontFeatureGroup featureGroup, NS
591594
/// <remarks>To be added.</remarks>
592595
protected int FeatureWeak {
593596
get {
594-
return (int) (NSNumber) Dictionary [CTFontFeatureSelectorKey.Identifier];
597+
var number = (NSNumber?) Dictionary [CTFontFeatureSelectorKey.Identifier];
598+
if (number is null)
599+
return default;
600+
return (int) number;
595601
}
596602
}
597603

@@ -2327,7 +2333,10 @@ internal CTFontFeatureSettings (NSDictionary dictionary)
23272333
/// <remarks>To be added.</remarks>
23282334
public FontFeatureGroup FeatureGroup {
23292335
get {
2330-
return (FontFeatureGroup) (int) (NSNumber) Dictionary [CTFontFeatureKey.Identifier];
2336+
var number = (NSNumber?) Dictionary [CTFontFeatureKey.Identifier];
2337+
if (number is null)
2338+
return default;
2339+
return (FontFeatureGroup) (int) number;
23312340
}
23322341
}
23332342

@@ -2336,7 +2345,10 @@ public FontFeatureGroup FeatureGroup {
23362345
/// <remarks>To be added.</remarks>
23372346
public int FeatureWeak {
23382347
get {
2339-
return (int) (NSNumber) Dictionary [CTFontFeatureSelectorKey.Identifier];
2348+
var number = (NSNumber?) Dictionary [CTFontFeatureSelectorKey.Identifier];
2349+
if (number is null)
2350+
return default;
2351+
return (int) number;
23402352
}
23412353
}
23422354
}
@@ -2375,32 +2387,32 @@ public CTFontVariationAxes (NSDictionary dictionary)
23752387
/// <summary>To be added.</summary>
23762388
/// <value>To be added.</value>
23772389
/// <remarks>To be added.</remarks>
2378-
public NSNumber Identifier {
2379-
get { return (NSNumber) Dictionary [CTFontVariationAxisKey.Identifier]; }
2390+
public NSNumber? Identifier {
2391+
get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.Identifier]; }
23802392
set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.Identifier, value); }
23812393
}
23822394

23832395
/// <summary>To be added.</summary>
23842396
/// <value>To be added.</value>
23852397
/// <remarks>To be added.</remarks>
2386-
public NSNumber MinimumValue {
2387-
get { return (NSNumber) Dictionary [CTFontVariationAxisKey.MinimumValue]; }
2398+
public NSNumber? MinimumValue {
2399+
get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.MinimumValue]; }
23882400
set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.MinimumValue, value); }
23892401
}
23902402

23912403
/// <summary>To be added.</summary>
23922404
/// <value>To be added.</value>
23932405
/// <remarks>To be added.</remarks>
2394-
public NSNumber MaximumValue {
2395-
get { return (NSNumber) Dictionary [CTFontVariationAxisKey.MaximumValue]; }
2406+
public NSNumber? MaximumValue {
2407+
get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.MaximumValue]; }
23962408
set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.MaximumValue, value); }
23972409
}
23982410

23992411
/// <summary>To be added.</summary>
24002412
/// <value>To be added.</value>
24012413
/// <remarks>To be added.</remarks>
2402-
public NSNumber DefaultValue {
2403-
get { return (NSNumber) Dictionary [CTFontVariationAxisKey.DefaultValue]; }
2414+
public NSNumber? DefaultValue {
2415+
get { return (NSNumber?) Dictionary [CTFontVariationAxisKey.DefaultValue]; }
24042416
set { Adapter.SetValue (Dictionary, CTFontVariationAxisKey.DefaultValue, value); }
24052417
}
24062418

src/CoreText/CTFontDescriptor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public IEnumerable<CTFontDescriptor>? CascadeList {
315315
/// <remarks>
316316
/// </remarks>
317317
public NSCharacterSet? CharacterSet {
318-
get { return (NSCharacterSet) Dictionary [CTFontDescriptorAttributeKey.CharacterSet]; }
318+
get { return (NSCharacterSet) Dictionary [CTFontDescriptorAttributeKey.CharacterSet]!; }
319319
set { Adapter.SetValue (Dictionary, CTFontDescriptorAttributeKey.CharacterSet!, value); }
320320
}
321321

@@ -515,7 +515,7 @@ public bool? WeakEnabled {
515515
/// </remarks>
516516
public bool Enabled {
517517
get {
518-
var value = (NSNumber) Dictionary [CTFontDescriptorAttributeKey.Enabled];
518+
var value = (NSNumber?) Dictionary [CTFontDescriptorAttributeKey.Enabled];
519519
if (value is null)
520520
return false;
521521
return value.Int32Value != 0;

src/CoreText/CTTextTab.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ public CTTextTabOptions (NSDictionary dictionary)
6363
/// <summary>To be added.</summary>
6464
/// <value>To be added.</value>
6565
/// <remarks>To be added.</remarks>
66-
public NSCharacterSet ColumnTerminators {
67-
get { return (NSCharacterSet) Dictionary [CTTextTabOptionKey.ColumnTerminators]; }
66+
public NSCharacterSet? ColumnTerminators {
67+
get { return (NSCharacterSet?) Dictionary [CTTextTabOptionKey.ColumnTerminators]!; }
6868
set { Adapter.SetValue (Dictionary, CTTextTabOptionKey.ColumnTerminators, value); }
6969
}
7070
}

src/Foundation/NSDictionary.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
//
2424
using System.Collections;
2525
using System.Collections.Generic;
26+
using System.Diagnostics.CodeAnalysis;
2627

2728
// Disable until we get around to enable + fix any issues.
2829
#nullable disable
@@ -472,13 +473,13 @@ public bool TryGetValue (NSObject key, out NSObject value)
472473
return value is not null;
473474
}
474475

475-
/// <param name="key">Key to lookup</param>
476-
/// <summary>Returns the value associated from a key in the dictionary, or null if the key is not found.</summary>
477-
/// <value>
478-
/// </value>
479-
/// <remarks>
480-
/// </remarks>
481-
public virtual NSObject this [NSObject key] {
476+
#nullable enable
477+
/// <summary>Gets the object associated with the specified key.</summary>
478+
/// <param name="key">The key of the object to get.</param>
479+
/// <value>The object associated with the specified key.</value>
480+
/// <remarks>Returns <see langword="null" /> if the key wasn't found.</remarks>
481+
[DisallowNull] // don't allow setting null values
482+
public virtual NSObject? this [NSObject key] {
482483
get {
483484
return ObjectForKey (key);
484485
}
@@ -487,13 +488,12 @@ public virtual NSObject this [NSObject key] {
487488
}
488489
}
489490

490-
/// <param name="key">Key to lookup</param>
491-
/// <summary>Returns the value associated from a key in the dictionary, or null if the key is not found.</summary>
492-
/// <value>
493-
/// </value>
494-
/// <remarks>
495-
/// </remarks>
496-
public virtual NSObject this [NSString key] {
491+
/// <summary>Gets the object associated with the specified key.</summary>
492+
/// <param name="key">The key of the object to get.</param>
493+
/// <value>The object associated with the specified key.</value>
494+
/// <remarks>Returns <see langword="null" /> if the key wasn't found.</remarks>
495+
[DisallowNull] // don't allow setting null values
496+
public virtual NSObject? this [NSString key] {
497497
get {
498498
return ObjectForKey (key);
499499
}
@@ -502,12 +502,13 @@ public virtual NSObject this [NSString key] {
502502
}
503503
}
504504

505-
/// <param name="key">Key to lookup</param>
506-
/// <summary>Returns the value associated from a key in the dictionary, or null if the key is not found.</summary>
507-
/// <value>
508-
/// </value>
509-
/// <remarks>The string will be marshalled as an NSString before performing the lookup.</remarks>
510-
public virtual NSObject this [string key] {
505+
/// <summary>Gets the object associated with the specified key.</summary>
506+
/// <param name="key">The key of the object to get.</param>
507+
/// <value>The object associated with the specified key.</value>
508+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="key"/> is <see langword="null"/>.</exception>
509+
/// <remarks>Returns <see langword="null" /> if the key wasn't found.</remarks>
510+
[DisallowNull] // don't allow setting null values
511+
public virtual NSObject? this [string key] {
511512
get {
512513
if (key is null)
513514
throw new ArgumentNullException ("key");
@@ -522,6 +523,7 @@ public virtual NSObject this [string key] {
522523
throw new NotSupportedException ();
523524
}
524525
}
526+
#nullable disable
525527

526528
ICollection<NSObject> IDictionary<NSObject, NSObject>.Keys {
527529
get { return Keys; }

0 commit comments

Comments
 (0)