Skip to content

Commit 253cb96

Browse files
committed
Added more nullability annotations to helper methods
1 parent 7b49dae commit 253cb96

File tree

5 files changed

+60
-10
lines changed

5 files changed

+60
-10
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if NETSTANDARD2_0
6+
7+
namespace System.Diagnostics.CodeAnalysis
8+
{
9+
/// <summary>
10+
/// Specifies that an output will not be null even if the corresponding type allows it.
11+
/// Specifies that an input argument was not null when the call returns.
12+
/// </summary>
13+
/// <remarks>Internal copy from the BCL attribute.</remarks>
14+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
15+
internal sealed class NotNullAttribute : Attribute
16+
{
17+
}
18+
}
19+
20+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if NETSTANDARD2_0
6+
7+
namespace System.Diagnostics.CodeAnalysis
8+
{
9+
/// <summary>
10+
/// Specifies that the output will be non-null if the named parameter is non-null.
11+
/// </summary>
12+
/// <remarks>Internal copy from the BCL attribute.</remarks>
13+
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
14+
internal sealed class NotNullIfNotNullAttribute : Attribute
15+
{
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="NotNullIfNotNullAttribute"/> class.
18+
/// </summary>
19+
/// <param name="parameterName"> The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.</param>
20+
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
21+
22+
/// <summary>Gets the associated parameter name.</summary>
23+
public string ParameterName { get; }
24+
}
25+
}
26+
27+
#endif

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableObject.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System;
1919
using System.Collections.Generic;
2020
using System.ComponentModel;
21+
using System.Diagnostics.CodeAnalysis;
2122
using System.Runtime.CompilerServices;
2223
using System.Threading.Tasks;
2324

@@ -84,7 +85,7 @@ protected void OnPropertyChanging([CallerMemberName] string? propertyName = null
8485
/// The <see cref="PropertyChanging"/> and <see cref="PropertyChanged"/> events are not raised
8586
/// if the current and new value for the target property are the same.
8687
/// </remarks>
87-
protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string? propertyName = null)
88+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null)
8889
{
8990
// We duplicate the code here instead of calling the overload because we can't
9091
// guarantee that the invoked SetProperty<T> will be inlined, and we need the JIT
@@ -120,7 +121,7 @@ protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string
120121
/// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
121122
/// <param name="propertyName">(optional) The name of the property that changed.</param>
122123
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
123-
protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
124+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, IEqualityComparer<T> comparer, [CallerMemberName] string? propertyName = null)
124125
{
125126
if (comparer.Equals(field, newValue))
126127
{
@@ -340,7 +341,7 @@ protected bool SetProperty<TModel, T>(T oldValue, T newValue, IEqualityComparer<
340341
/// indicates that the new value being assigned to <paramref name="taskNotifier"/> is different than the previous one,
341342
/// and it does not mean the new <see cref="Task"/> instance passed as argument is in any particular state.
342343
/// </remarks>
343-
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
344+
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null)
344345
{
345346
// We invoke the overload with a callback here to avoid code duplication, and simply pass an empty callback.
346347
// The lambda expression here is transformed by the C# compiler into an empty closure class with a
@@ -368,7 +369,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
368369
/// The <see cref="PropertyChanging"/> and <see cref="PropertyChanged"/> events are not raised
369370
/// if the current and new value for the target property are the same.
370371
/// </remarks>
371-
protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
372+
protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, Action<Task?> callback, [CallerMemberName] string? propertyName = null)
372373
{
373374
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
374375
}
@@ -407,7 +408,7 @@ protected bool SetPropertyAndNotifyOnCompletion(ref TaskNotifier? taskNotifier,
407408
/// indicates that the new value being assigned to <paramref name="taskNotifier"/> is different than the previous one,
408409
/// and it does not mean the new <see cref="Task{TResult}"/> instance passed as argument is in any particular state.
409410
/// </remarks>
410-
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
411+
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, [CallerMemberName] string? propertyName = null)
411412
{
412413
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, static _ => { }, propertyName);
413414
}
@@ -430,7 +431,7 @@ protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNoti
430431
/// The <see cref="PropertyChanging"/> and <see cref="PropertyChanged"/> events are not raised
431432
/// if the current and new value for the target property are the same.
432433
/// </remarks>
433-
protected bool SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
434+
protected bool SetPropertyAndNotifyOnCompletion<T>([NotNull] ref TaskNotifier<T>? taskNotifier, Task<T>? newValue, Action<Task<T>?> callback, [CallerMemberName] string? propertyName = null)
434435
{
435436
return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new(), newValue, callback, propertyName);
436437
}

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableRecipient.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
using System;
1818
using System.Collections.Generic;
19+
using System.Diagnostics.CodeAnalysis;
1920
using System.Runtime.CompilerServices;
2021
using Microsoft.Toolkit.Mvvm.Messaging;
2122
using Microsoft.Toolkit.Mvvm.Messaging.Messages;
@@ -145,7 +146,7 @@ protected virtual void Broadcast<T>(T oldValue, T newValue, string? propertyName
145146
/// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
146147
/// are not raised if the current and new value for the target property are the same.
147148
/// </remarks>
148-
protected bool SetProperty<T>(ref T field, T newValue, bool broadcast, [CallerMemberName] string? propertyName = null)
149+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, bool broadcast, [CallerMemberName] string? propertyName = null)
149150
{
150151
T oldValue = field;
151152

@@ -174,7 +175,7 @@ protected bool SetProperty<T>(ref T field, T newValue, bool broadcast, [CallerMe
174175
/// <param name="broadcast">If <see langword="true"/>, <see cref="Broadcast{T}"/> will also be invoked.</param>
175176
/// <param name="propertyName">(optional) The name of the property that changed.</param>
176177
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
177-
protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, bool broadcast, [CallerMemberName] string? propertyName = null)
178+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, IEqualityComparer<T> comparer, bool broadcast, [CallerMemberName] string? propertyName = null)
178179
{
179180
T oldValue = field;
180181

Microsoft.Toolkit.Mvvm/ComponentModel/ObservableValidator.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Generic;
88
using System.ComponentModel;
99
using System.ComponentModel.DataAnnotations;
10+
using System.Diagnostics.CodeAnalysis;
1011
using System.Diagnostics.Contracts;
1112
using System.Linq;
1213
using System.Linq.Expressions;
@@ -137,7 +138,7 @@ protected ObservableValidator(ValidationContext validationContext)
137138
/// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
138139
/// are not raised if the current and new value for the target property are the same.
139140
/// </remarks>
140-
protected bool SetProperty<T>(ref T field, T newValue, bool validate, [CallerMemberName] string? propertyName = null)
141+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, bool validate, [CallerMemberName] string? propertyName = null)
141142
{
142143
bool propertyChanged = SetProperty(ref field, newValue, propertyName);
143144

@@ -162,7 +163,7 @@ protected bool SetProperty<T>(ref T field, T newValue, bool validate, [CallerMem
162163
/// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
163164
/// <param name="propertyName">(optional) The name of the property that changed.</param>
164165
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
165-
protected bool SetProperty<T>(ref T field, T newValue, IEqualityComparer<T> comparer, bool validate, [CallerMemberName] string? propertyName = null)
166+
protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, IEqualityComparer<T> comparer, bool validate, [CallerMemberName] string? propertyName = null)
166167
{
167168
bool propertyChanged = SetProperty(ref field, newValue, comparer, propertyName);
168169

0 commit comments

Comments
 (0)