Skip to content

Commit f6a0f3f

Browse files
committed
Add null checks to public APIs
1 parent 08fca92 commit f6a0f3f

5 files changed

+102
-7
lines changed

CommunityToolkit.Mvvm/Collections/ObservableGroupedCollectionExtensions.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@ public static class ObservableGroupedCollectionExtensions
2424
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
2525
/// <param name="key">The key of the group to query.</param>
2626
/// <returns>The first group matching <paramref name="key"/>.</returns>
27+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
2728
/// <exception cref="InvalidOperationException">The target group does not exist.</exception>
2829
public static ObservableGroup<TKey, TElement> FirstGroupByKey<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key)
2930
where TKey : notnull
3031
{
32+
ArgumentNullException.ThrowIfNull(source);
33+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
34+
3135
ObservableGroup<TKey, TElement>? group = source.FirstGroupByKeyOrDefault(key);
3236

3337
if (group is null)
@@ -52,9 +56,13 @@ static void ThrowArgumentExceptionForKeyNotFound()
5256
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
5357
/// <param name="key">The key of the group to query.</param>
5458
/// <returns>The first group matching <paramref name="key"/> or null.</returns>
59+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
5560
public static ObservableGroup<TKey, TElement>? FirstGroupByKeyOrDefault<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key)
5661
where TKey : notnull
5762
{
63+
ArgumentNullException.ThrowIfNull(source);
64+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
65+
5866
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
5967
{
6068
foreach (ObservableGroup<TKey, TElement>? group in list)
@@ -85,9 +93,13 @@ static void ThrowArgumentExceptionForKeyNotFound()
8593
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
8694
/// <param name="key">The key of the group to add.</param>
8795
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
96+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
8897
public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key)
8998
where TKey : notnull
9099
{
100+
ArgumentNullException.ThrowIfNull(source);
101+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
102+
91103
ObservableGroup<TKey, TElement> group = new(key);
92104

93105
source.Add(group);
@@ -103,9 +115,13 @@ public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this Obse
103115
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
104116
/// <param name="grouping">The group of items to add.</param>
105117
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
118+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="grouping"/> are <see langword="null"/>.</exception>
106119
public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, IGrouping<TKey, TElement> grouping)
107120
where TKey : notnull
108121
{
122+
ArgumentNullException.ThrowIfNull(source);
123+
ArgumentNullException.ThrowIfNull(grouping);
124+
109125
ObservableGroup<TKey, TElement> group = new(grouping);
110126

111127
source.Add(group);
@@ -122,9 +138,14 @@ public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this Obse
122138
/// <param name="key">The key of the group where <paramref name="collection"/> will be added.</param>
123139
/// <param name="collection">The collection to add.</param>
124140
/// <returns>The added <see cref="ObservableGroup{TKey, TElement}"/>.</returns>
141+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="key"/> or <paramref name="collection"/> are <see langword="null"/>.</exception>
125142
public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, IEnumerable<TElement> collection)
126143
where TKey : notnull
127144
{
145+
ArgumentNullException.ThrowIfNull(source);
146+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
147+
ArgumentNullException.ThrowIfNull(collection);
148+
128149
ObservableGroup<TKey, TElement> group = new(key, collection);
129150

130151
source.Add(group);
@@ -140,9 +161,13 @@ public static ObservableGroup<TKey, TElement> AddGroup<TKey, TElement>(this Obse
140161
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
141162
/// <param name="key">The key of the group to add.</param>
142163
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
164+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
143165
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key)
144166
where TKey : notnull
145167
{
168+
ArgumentNullException.ThrowIfNull(source);
169+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
170+
146171
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
147172
{
148173
int index = 0;
@@ -197,9 +222,13 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
197222
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TElement}"/> instance.</param>
198223
/// <param name="grouping">The group of items to add.</param>
199224
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
225+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="grouping"/> are <see langword="null"/>.</exception>
200226
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, IGrouping<TKey, TElement> grouping)
201227
where TKey : notnull
202228
{
229+
ArgumentNullException.ThrowIfNull(source);
230+
ArgumentNullException.ThrowIfNull(grouping);
231+
203232
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
204233
{
205234
int index = 0;
@@ -255,9 +284,14 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
255284
/// <param name="key">The key of the group where <paramref name="collection"/> will be added.</param>
256285
/// <param name="collection">The collection to add.</param>
257286
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
287+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="key"/> or <paramref name="collection"/> are <see langword="null"/>.</exception>
258288
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, IEnumerable<TElement> collection)
259289
where TKey : notnull
260290
{
291+
ArgumentNullException.ThrowIfNull(source);
292+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
293+
ArgumentNullException.ThrowIfNull(collection);
294+
261295
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
262296
{
263297
int index = 0;
@@ -313,9 +347,14 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
313347
/// <param name="key">The key of the group to add.</param>
314348
/// <param name="comparer">The <see cref="IComparer{T}"/> instance to insert <typeparamref name="TKey"/> at the right position.</param>
315349
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
350+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="key"/> or <paramref name="comparer"/> are <see langword="null"/>.</exception>
316351
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, IComparer<TKey> comparer)
317352
where TKey : notnull
318353
{
354+
ArgumentNullException.ThrowIfNull(source);
355+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
356+
ArgumentNullException.ThrowIfNull(comparer);
357+
319358
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
320359
{
321360
int index = 0;
@@ -371,9 +410,14 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
371410
/// <param name="grouping">The group of items to add.</param>
372411
/// <param name="comparer">The <see cref="IComparer{T}"/> instance to insert <typeparamref name="TKey"/> at the right position.</param>
373412
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
413+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="grouping"/> or <paramref name="comparer"/> are <see langword="null"/>.</exception>
374414
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, IGrouping<TKey, TElement> grouping, IComparer<TKey> comparer)
375415
where TKey : notnull
376416
{
417+
ArgumentNullException.ThrowIfNull(source);
418+
ArgumentNullException.ThrowIfNull(grouping);
419+
ArgumentNullException.ThrowIfNull(comparer);
420+
377421
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
378422
{
379423
int index = 0;
@@ -430,9 +474,15 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
430474
/// <param name="comparer">The <see cref="IComparer{T}"/> instance to insert <typeparamref name="TKey"/> at the right position.</param>
431475
/// <param name="collection">The collection to add.</param>
432476
/// <returns>The added <see cref="ObservableGroup{TKey, TValue}"/>.</returns>
477+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="key"/>, <paramref name="comparer"/> or <paramref name="collection"/> are <see langword="null"/>.</exception>
433478
public static ObservableGroup<TKey, TElement> InsertGroup<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, IComparer<TKey> comparer, IEnumerable<TElement> collection)
434479
where TKey : notnull
435480
{
481+
ArgumentNullException.ThrowIfNull(source);
482+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
483+
ArgumentNullException.ThrowIfNull(comparer);
484+
ArgumentNullException.ThrowIfNull(collection);
485+
436486
if (source.TryGetList(out List<ObservableGroup<TKey, TElement>>? list))
437487
{
438488
int index = 0;
@@ -489,9 +539,13 @@ static ObservableGroup<TKey, TElement> InsertGroupFallback(ObservableGroupedColl
489539
/// <param name="key">The key of the group where the <paramref name="item"/> should be added.</param>
490540
/// <param name="item">The item to add.</param>
491541
/// <returns>The instance of the <see cref="ObservableGroup{TKey, TElement}"/> which will receive the value. It will either be an existing group or a new group.</returns>
542+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
492543
public static ObservableGroup<TKey, TElement> AddItem<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, TElement item)
493544
where TKey : notnull
494545
{
546+
ArgumentNullException.ThrowIfNull(source);
547+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
548+
495549
ObservableGroup<TKey, TElement>? group = source.FirstGroupByKeyOrDefault(key);
496550

497551
if (group is null)
@@ -517,9 +571,13 @@ public static ObservableGroup<TKey, TElement> AddItem<TKey, TElement>(this Obser
517571
/// <param name="key">The key of the group where to insert <paramref name="item"/>.</param>
518572
/// <param name="item">The item to add.</param>
519573
/// <returns>The instance of the <see cref="ObservableGroup{TKey, TElement}"/> which will receive the value.</returns>
574+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
520575
public static ObservableGroup<TKey, TElement> InsertItem<TKey, TElement>(this ObservableGroupedCollection<TKey, TElement> source, TKey key, TElement item)
521576
where TKey : notnull
522577
{
578+
ArgumentNullException.ThrowIfNull(source);
579+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
580+
523581
ObservableGroup<TKey, TElement>? group = source.FirstGroupByKeyOrDefault(key);
524582

525583
if (group is null)
@@ -580,6 +638,7 @@ static void InsertItemFallback(ObservableCollection<TElement> source, TElement i
580638
/// <param name="item">The item to add.</param>
581639
/// <param name="itemComparer">The <see cref="IComparer{T}"/> instance to compare elements.</param>
582640
/// <returns>The instance of the <see cref="ObservableGroup{TKey, TElement}"/> which will receive the value.</returns>
641+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/>, <paramref name="key"/>, <paramref name="keyComparer"/> or <paramref name="itemComparer"/> are <see langword="null"/>.</exception>
583642
public static ObservableGroup<TKey, TElement> InsertItem<TKey, TElement>(
584643
this ObservableGroupedCollection<TKey, TElement> source,
585644
TKey key,
@@ -588,6 +647,11 @@ public static ObservableGroup<TKey, TElement> InsertItem<TKey, TElement>(
588647
IComparer<TElement> itemComparer)
589648
where TKey : notnull
590649
{
650+
ArgumentNullException.ThrowIfNull(source);
651+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
652+
ArgumentNullException.ThrowIfNull(keyComparer);
653+
ArgumentNullException.ThrowIfNull(itemComparer);
654+
591655
ObservableGroup<TKey, TElement>? group = source.FirstGroupByKeyOrDefault(key);
592656

593657
if (group is null)
@@ -645,9 +709,13 @@ static void InsertItemFallback(ObservableCollection<TElement> source, TElement i
645709
/// <typeparam name="TValue">The type of the items in the collection.</typeparam>
646710
/// <param name="source">The source <see cref="ObservableGroupedCollection{TKey, TValue}"/> instance.</param>
647711
/// <param name="key">The key of the group to remove.</param>
712+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
648713
public static void RemoveGroup<TKey, TValue>(this ObservableGroupedCollection<TKey, TValue> source, TKey key)
649714
where TKey : notnull
650715
{
716+
ArgumentNullException.ThrowIfNull(source);
717+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
718+
651719
if (source.TryGetList(out List<ObservableGroup<TKey, TValue>>? list))
652720
{
653721
int index = 0;
@@ -697,9 +765,13 @@ static void RemoveGroupFallback(ObservableGroupedCollection<TKey, TValue> source
697765
/// <param name="key">The key of the group where the <paramref name="item"/> should be removed.</param>
698766
/// <param name="item">The item to remove.</param>
699767
/// <param name="removeGroupIfEmpty">If true (default value), the group will be removed once it becomes empty.</param>
768+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="source"/> or <paramref name="key"/> are <see langword="null"/>.</exception>
700769
public static void RemoveItem<TKey, TValue>(this ObservableGroupedCollection<TKey, TValue> source, TKey key, TValue item, bool removeGroupIfEmpty = true)
701770
where TKey : notnull
702771
{
772+
ArgumentNullException.ThrowIfNull(source);
773+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
774+
703775
if (source.TryGetList(out List<ObservableGroup<TKey, TValue>>? list))
704776
{
705777
int index = 0;

CommunityToolkit.Mvvm/Collections/ObservableGroupedCollection{TKey,TElement}.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,20 @@ public ObservableGroupedCollection()
2929
/// Initializes a new instance of the <see cref="ObservableGroupedCollection{TKey, TValue}"/> class.
3030
/// </summary>
3131
/// <param name="collection">The initial data to add in the grouped collection.</param>
32+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="collection"/> is <see langword="null"/>.</exception>
3233
public ObservableGroupedCollection(IEnumerable<IGrouping<TKey, TElement>> collection)
33-
: base(collection.Select(static group => new ObservableGroup<TKey, TElement>(group)))
34+
: base(collection?.Select(static group => new ObservableGroup<TKey, TElement>(group))!)
3435
{
3536
}
3637

3738
/// <inheritdoc/>
3839
IEnumerable<TElement> ILookup<TKey, TElement>.this[TKey key]
3940
{
40-
// TODO: optimize this
41-
get => Enumerable.FirstOrDefault<ObservableGroup<TKey, TElement>>(this, item => EqualityComparer<TKey>.Default.Equals(item.Key, key)) ?? Enumerable.Empty<TElement>();
41+
get
42+
{
43+
// TODO: optimize this
44+
return Enumerable.FirstOrDefault<ObservableGroup<TKey, TElement>>(this, item => EqualityComparer<TKey>.Default.Equals(item.Key, key)) ?? Enumerable.Empty<TElement>();
45+
}
4246
}
4347

4448
/// <summary>

CommunityToolkit.Mvvm/Collections/ObservableGroup{TKey,TElement}.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ public sealed class ObservableGroup<TKey, TElement> : ObservableCollection<TElem
2626
/// Initializes a new instance of the <see cref="ObservableGroup{TKey, TValue}"/> class.
2727
/// </summary>
2828
/// <param name="key">The key for the group.</param>
29+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="key"/> is <see langword="null"/>.</exception>
2930
public ObservableGroup(TKey key)
3031
{
32+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
33+
3134
this.key = key;
3235
}
3336

3437
/// <summary>
3538
/// Initializes a new instance of the <see cref="ObservableGroup{TKey, TValue}"/> class.
3639
/// </summary>
3740
/// <param name="grouping">The grouping to fill the group.</param>
41+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="grouping"/> is <see langword="null"/>.</exception>
3842
public ObservableGroup(IGrouping<TKey, TElement> grouping)
3943
: base(grouping)
4044
{
@@ -46,9 +50,12 @@ public ObservableGroup(IGrouping<TKey, TElement> grouping)
4650
/// </summary>
4751
/// <param name="key">The key for the group.</param>
4852
/// <param name="collection">The initial collection of data to add to the group.</param>
53+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="key"/> or <paramref name="collection"/> are <see langword="null"/>.</exception>
4954
public ObservableGroup(TKey key, IEnumerable<TElement> collection)
5055
: base(collection)
5156
{
57+
ArgumentNullException.For<TKey>.ThrowIfNull(key);
58+
5259
this.key = key;
5360
}
5461

@@ -57,11 +64,14 @@ public ObservableGroup(TKey key, IEnumerable<TElement> collection)
5764
/// <summary>
5865
/// Gets or sets the key of the group.
5966
/// </summary>
67+
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="value"/> is <see langword="null"/>.</exception>
6068
public TKey Key
6169
{
6270
get => this.key;
6371
set
6472
{
73+
ArgumentNullException.For<TKey>.ThrowIfNull(value);
74+
6575
if (!EqualityComparer<TKey>.Default.Equals(this.key!, value))
6676
{
6777
this.key = value;

0 commit comments

Comments
 (0)