From ed1960e265e1d5d67f92706f1cc3c4dd03079534 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 12:43:10 +0300 Subject: [PATCH 01/21] Annotate src --- .../src/CancellationChangeToken.cs | 2 +- .../src/ChangeToken.cs | 12 +- .../src/CompositeChangeToken.cs | 27 ++-- .../src/IChangeToken.cs | 2 +- .../Microsoft.Extensions.Primitives.csproj | 1 + .../src/StringSegment.cs | 12 +- .../src/StringTokenizer.cs | 1 - .../src/StringValues.cs | 131 +++++++++--------- .../src/ThrowHelper.cs | 6 + 9 files changed, 103 insertions(+), 91 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/CancellationChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/CancellationChangeToken.cs index f66878f9e8eb9c..758d287ad30fea 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/CancellationChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/CancellationChangeToken.cs @@ -29,7 +29,7 @@ public CancellationChangeToken(CancellationToken cancellationToken) private CancellationToken Token { get; } /// - public IDisposable RegisterChangeCallback(Action callback, object state) + public IDisposable RegisterChangeCallback(Action callback, object? state) { #if NETCOREAPP || NETSTANDARD2_1 try diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index b5df90f760537a..7e00d5f4ff3e52 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -58,7 +58,7 @@ private sealed class ChangeTokenRegistration : IDisposable private readonly Func _changeTokenProducer; private readonly Action _changeTokenConsumer; private readonly TState _state; - private IDisposable _disposable; + private IDisposable? _disposable; private static readonly NoopDisposable _disposedSentinel = new NoopDisposable(); @@ -100,7 +100,7 @@ private void RegisterChangeTokenCallback(IChangeToken token) return; } - IDisposable registraton = token.RegisterChangeCallback(s => ((ChangeTokenRegistration)s).OnChangeTokenFired(), this); + IDisposable registraton = token.RegisterChangeCallback(s => ((ChangeTokenRegistration?)s)?.OnChangeTokenFired(), this); SetDisposable(registraton); } @@ -110,7 +110,7 @@ private void SetDisposable(IDisposable disposable) // We don't want to transition from _disposedSentinel => anything since it's terminal // but we want to allow going from previously assigned disposable, to another // disposable. - IDisposable current = Volatile.Read(ref _disposable); + IDisposable? current = Volatile.Read(ref _disposable); // If Dispose was called, then immediately dispose the disposable if (current == _disposedSentinel) @@ -120,7 +120,7 @@ private void SetDisposable(IDisposable disposable) } // Otherwise, try to update the disposable - IDisposable previous = Interlocked.CompareExchange(ref _disposable, disposable, current); + IDisposable? previous = Interlocked.CompareExchange(ref _disposable, disposable, current); if (previous == _disposedSentinel) { @@ -129,7 +129,7 @@ private void SetDisposable(IDisposable disposable) } else if (previous == current) { - // We successfuly assigned the _disposable field to disposable + // We successfully assigned the _disposable field to disposable } else { @@ -142,7 +142,7 @@ public void Dispose() { // If the previous value is disposable then dispose it, otherwise, // now we've set the disposed sentinel - Interlocked.Exchange(ref _disposable, _disposedSentinel).Dispose(); + Interlocked.Exchange(ref _disposable, _disposedSentinel)?.Dispose(); } private sealed class NoopDisposable : IDisposable diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs index 6f20b657a5bfe7..66eb544cf47895 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Threading; namespace Microsoft.Extensions.Primitives @@ -13,11 +14,14 @@ namespace Microsoft.Extensions.Primitives /// public class CompositeChangeToken : IChangeToken { - private static readonly Action _onChangeDelegate = OnChange; - private readonly object _callbackLock = new object(); - private CancellationTokenSource _cancellationTokenSource; - private bool _registeredCallbackProxy; - private List _disposables; + private static readonly Action _onChangeDelegate = OnChange; + private readonly object _callbackLock = new(); + private CancellationTokenSource? _cancellationTokenSource; + private List? _disposables; + + [MemberNotNullWhen(true, nameof(_cancellationTokenSource))] + [MemberNotNullWhen(true, nameof(_disposables))] + private bool _registeredCallbackProxy { get; set; } /// /// Creates a new instance of . @@ -42,7 +46,7 @@ public CompositeChangeToken(IReadOnlyList changeTokens) public IReadOnlyList ChangeTokens { get; } /// - public IDisposable RegisterChangeCallback(Action callback, object state) + public IDisposable RegisterChangeCallback(Action callback, object? state) { EnsureCallbacksInitialized(); return _cancellationTokenSource.Token.Register(callback, state); @@ -74,6 +78,8 @@ public bool HasChanged /// public bool ActiveChangeCallbacks { get; } + [MemberNotNull(nameof(_cancellationTokenSource))] + [MemberNotNull(nameof(_disposables))] private void EnsureCallbacksInitialized() { if (_registeredCallbackProxy) @@ -102,10 +108,10 @@ private void EnsureCallbacksInitialized() } } - private static void OnChange(object state) + private static void OnChange(object? state) { - var compositeChangeTokenState = (CompositeChangeToken)state; - if (compositeChangeTokenState._cancellationTokenSource == null) + var compositeChangeTokenState = (CompositeChangeToken?)state; + if (compositeChangeTokenState?._cancellationTokenSource == null) { return; } @@ -121,13 +127,12 @@ private static void OnChange(object state) } } - List disposables = compositeChangeTokenState._disposables; + List? disposables = compositeChangeTokenState._disposables; Debug.Assert(disposables != null); for (int i = 0; i < disposables.Count; i++) { disposables[i].Dispose(); } - } } } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs index b1c336d30bdc6f..f34122c21f723e 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs @@ -28,6 +28,6 @@ public interface IChangeToken /// The to invoke. /// State to be passed into the callback. /// An that is used to unregister the callback. - IDisposable RegisterChangeCallback(Action callback, object state); + IDisposable RegisterChangeCallback(Action callback, object? state); } } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj b/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj index 5f2911b00eccef..369c1d06dd1ce3 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj +++ b/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);netcoreapp3.1;netstandard2.0;net461 + enable true true diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs index c5a70270e5677c..4b73f1ff2dad6d 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace Microsoft.Extensions.Primitives @@ -76,11 +77,12 @@ public StringSegment(string buffer, int offset, int length) /// /// Gets the value of this segment as a . /// - public string Value => HasValue ? Buffer.Substring(Offset, Length) : null; + public string? Value => HasValue ? Buffer.Substring(Offset, Length) : null; /// /// Gets whether this contains a valid value. /// + [MemberNotNullWhen(true, nameof(Buffer))] public bool HasValue => Buffer != null; /// @@ -188,7 +190,7 @@ public static int Compare(StringSegment a, StringSegment b, StringComparison com /// /// An object to compare with this object. /// if the current object is equal to the other parameter; otherwise, . - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is StringSegment segment && Equals(segment); } @@ -681,7 +683,8 @@ private static void CheckStringComparison(StringComparison comparisonType) // Methods that do no return (i.e. throw) are not inlined // https://github.com/dotnet/coreclr/pull/6103 - private static void ThrowInvalidArguments(string buffer, int offset, int length) + [DoesNotReturn] + private static void ThrowInvalidArguments(string? buffer, int offset, int length) { // Only have single throw in method so is marked as "does not return" and isn't inlined to caller throw GetInvalidArgumentsException(); @@ -707,6 +710,7 @@ Exception GetInvalidArgumentsException() } } + [DoesNotReturn] private void ThrowInvalidArguments(int offset, int length, ExceptionArgument offsetOrStart) { throw GetInvalidArgumentsException(HasValue); @@ -733,7 +737,7 @@ Exception GetInvalidArgumentsException(bool hasValue) } /// - bool IEquatable.Equals(string other) + bool IEquatable.Equals(string? other) { // Explicit interface implementation for IEquatable because // the interface's Equals method allows null strings, which we return diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs index d3571852574761..869ab54a5b1a7c 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections; using System.Collections.Generic; diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 7a7ec59457a930..8c338b98a8ff3b 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -24,13 +24,13 @@ namespace Microsoft.Extensions.Primitives /// public static readonly StringValues Empty = new StringValues(Array.Empty()); - private readonly object _values; + private readonly object? _values; /// /// Initializes a new instance of the structure using the specified string. /// /// A string value or null. - public StringValues(string value) + public StringValues(string? value) { _values = value; } @@ -39,7 +39,7 @@ public StringValues(string value) /// Initializes a new instance of the structure using the specified array of strings. /// /// A string array. - public StringValues(string[] values) + public StringValues(string[]? values) { _values = values; } @@ -48,7 +48,7 @@ public StringValues(string[] values) /// Defines an implicit conversion of a given string to a . /// /// A string to implicitly convert. - public static implicit operator StringValues(string value) + public static implicit operator StringValues(string? value) { return new StringValues(value); } @@ -57,7 +57,7 @@ public static implicit operator StringValues(string value) /// Defines an implicit conversion of a given string array to a . /// /// A string array to implicitly convert. - public static implicit operator StringValues(string[] values) + public static implicit operator StringValues(string[]? values) { return new StringValues(values); } @@ -69,7 +69,7 @@ public static implicit operator StringValues(string[] values) /// Returns null where has been initialized from an empty string array or is . /// /// A to implicitly convert. - public static implicit operator string (StringValues values) + public static implicit operator string?(StringValues values) { return values.GetStringValue(); } @@ -78,7 +78,7 @@ public static implicit operator string (StringValues values) /// Defines an implicit conversion of a given to a string array. /// /// A to implicitly convert. - public static implicit operator string[] (StringValues value) + public static implicit operator string[]?(StringValues value) { return value.GetArrayValue(); } @@ -92,7 +92,7 @@ public int Count get { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is null) { return 0; @@ -109,10 +109,7 @@ public int Count } } - bool ICollection.IsReadOnly - { - get { return true; } - } + bool ICollection.IsReadOnly => true; /// /// Gets the at index. @@ -122,8 +119,8 @@ bool ICollection.IsReadOnly /// Set operations are not supported on readonly . string IList.this[int index] { - get { return this[index]; } - set { throw new NotSupportedException(); } + get => this[index]; + set => throw new NotSupportedException(); } /// @@ -137,7 +134,7 @@ public string this[int index] get { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is string str) { if (index == 0) @@ -170,10 +167,10 @@ public override string ToString() return GetStringValue() ?? string.Empty; } - private string GetStringValue() + private string? GetStringValue() { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is string s) { return s; @@ -183,7 +180,7 @@ private string GetStringValue() return GetStringValueFromArray(value); } - static string GetStringValueFromArray(object value) + static string? GetStringValueFromArray(object? value) { if (value is null) { @@ -193,12 +190,12 @@ static string GetStringValueFromArray(object value) Debug.Assert(value is string[]); // value is not null or string, array, can only be string[] string[] values = Unsafe.As(value); - switch (values.Length) + return values.Length switch { - case 0: return null; - case 1: return values[0]; - default: return GetJoinedStringValueFromArray(values); - } + 0 => null, + 1 => values[0], + _ => GetJoinedStringValueFromArray(values), + }; } static string GetJoinedStringValueFromArray(string[] values) @@ -213,7 +210,7 @@ static string GetJoinedStringValueFromArray(string[] values) { if (length > 0) { - // Add seperator + // Add separator length++; } @@ -232,7 +229,7 @@ static string GetJoinedStringValueFromArray(string[] values) { if (offset > 0) { - // Add seperator + // Add separator span[offset] = ','; offset++; } @@ -253,7 +250,7 @@ static string GetJoinedStringValueFromArray(string[] values) { if (hasAdded) { - // Add seperator + // Add separator sb.Append(','); } @@ -280,10 +277,10 @@ public string[] ToArray() return GetArrayValue() ?? Array.Empty(); } - private string[] GetArrayValue() + private string[]? GetArrayValue() { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is string[] values) { return values; @@ -312,7 +309,7 @@ int IList.IndexOf(string item) private int IndexOf(string item) { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is string[] values) { for (int i = 0; i < values.Length; i++) @@ -358,7 +355,7 @@ void ICollection.CopyTo(string[] array, int arrayIndex) private void CopyTo(string[] array, int arrayIndex) { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory - object value = _values; + object? value = _values; if (value is string[] values) { Array.Copy(values, 0, array, arrayIndex, values.Length); @@ -422,19 +419,19 @@ IEnumerator IEnumerable.GetEnumerator() /// true if value contains a single null or empty string or an empty array; otherwise, false. public static bool IsNullOrEmpty(StringValues value) { - object data = value._values; + object? data = value._values; if (data is null) { return true; } if (data is string[] values) { - switch (values.Length) + return values.Length switch { - case 0: return true; - case 1: return string.IsNullOrEmpty(values[0]); - default: return false; - } + 0 => true, + 1 => string.IsNullOrEmpty(values[0]), + _ => false, + }; } else { @@ -476,7 +473,7 @@ public static StringValues Concat(StringValues values1, StringValues values2) /// The to concatenate. /// The to concatenate. /// The concatenation of and . - public static StringValues Concat(in StringValues values, string value) + public static StringValues Concat(in StringValues values, string? value) { if (value == null) { @@ -501,7 +498,7 @@ public static StringValues Concat(in StringValues values, string value) /// The to concatenate. /// The to concatenate. /// The concatenation of and . - public static StringValues Concat(string value, in StringValues values) + public static StringValues Concat(string? value, in StringValues values) { if (value == null) { @@ -581,7 +578,7 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. If is null, the method returns false. - public static bool Equals(string left, StringValues right) => Equals(new StringValues(left), right); + public static bool Equals(string? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and objects have the same values. @@ -589,14 +586,14 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. If is null, the method returns false. - public static bool Equals(StringValues left, string right) => Equals(left, new StringValues(right)); + public static bool Equals(StringValues left, string? right) => Equals(left, new StringValues(right)); /// /// Determines whether this instance and a specified , have the same value. /// /// The to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. If is null, returns false. - public bool Equals(string other) => Equals(this, new StringValues(other)); + public bool Equals(string? other) => Equals(this, new StringValues(other)); /// /// Determines whether the specified string array and objects have the same values. @@ -604,7 +601,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(string[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool Equals(string[]? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and string array objects have the same values. @@ -612,17 +609,17 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(StringValues left, string[] right) => Equals(left, new StringValues(right)); + public static bool Equals(StringValues left, string[]? right) => Equals(left, new StringValues(right)); /// /// Determines whether this instance and a specified string array have the same values. /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals(string[] other) => Equals(this, new StringValues(other)); + public bool Equals(string[]? other) => Equals(this, new StringValues(other)); /// - public static bool operator ==(StringValues left, string right) => Equals(left, new StringValues(right)); + public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); /// /// Determines whether the specified and objects have different values. @@ -630,10 +627,10 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(StringValues left, string right) => !Equals(left, new StringValues(right)); + public static bool operator !=(StringValues left, string? right) => !Equals(left, new StringValues(right)); /// - public static bool operator ==(string left, StringValues right) => Equals(new StringValues(left), right); + public static bool operator ==(string? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and objects have different values. @@ -644,7 +641,7 @@ public static bool Equals(StringValues left, StringValues right) public static bool operator !=(string left, StringValues right) => !Equals(new StringValues(left), right); /// - public static bool operator ==(StringValues left, string[] right) => Equals(left, new StringValues(right)); + public static bool operator ==(StringValues left, string[]? right) => Equals(left, new StringValues(right)); /// /// Determines whether the specified and string array have different values. @@ -652,10 +649,10 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(StringValues left, string[] right) => !Equals(left, new StringValues(right)); + public static bool operator !=(StringValues left, string[]? right) => !Equals(left, new StringValues(right)); /// - public static bool operator ==(string[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool operator ==(string[]? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified string array and have different values. @@ -663,7 +660,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(string[] left, StringValues right) => !Equals(new StringValues(left), right); + public static bool operator !=(string[]? left, StringValues right) => !Equals(new StringValues(left), right); /// /// Determines whether the specified and , which must be a @@ -705,26 +702,26 @@ public static bool Equals(StringValues left, StringValues right) /// /// An object to compare with this object. /// true if the current object is equal to ; otherwise, false. - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj == null) { return Equals(this, StringValues.Empty); } - if (obj is string) + if (obj is string str) { - return Equals(this, (string)obj); + return Equals(this, str); } - if (obj is string[]) + if (obj is string[] array) { - return Equals(this, (string[])obj); + return Equals(this, array); } - if (obj is StringValues) + if (obj is StringValues stringValues) { - return Equals(this, (StringValues)obj); + return Equals(this, stringValues); } return false; @@ -733,7 +730,7 @@ public override bool Equals(object obj) /// public override int GetHashCode() { - object value = _values; + object? value = _values; if (value is string[] values) { if (Count == 1) @@ -756,13 +753,13 @@ public override int GetHashCode() /// /// Enumerates the string values of a . /// - public struct Enumerator : IEnumerator + public struct Enumerator : IEnumerator { - private readonly string[] _values; - private string _current; + private readonly string[]? _values; private int _index; + private string? _current; - internal Enumerator(object value) + internal Enumerator(object? value) { if (value is string str) { @@ -774,7 +771,7 @@ internal Enumerator(object value) _current = null; _values = Unsafe.As(value); } - _index = 0; + _index = 0; } public Enumerator(ref StringValues values) : this(values._values) @@ -788,7 +785,7 @@ public bool MoveNext() return false; } - string[] values = _values; + string[]? values = _values; if (values != null) { if ((uint)index < (uint)values.Length) @@ -806,9 +803,9 @@ public bool MoveNext() return _current != null; } - public string Current => _current; + public string? Current => _current; - object IEnumerator.Current => _current; + object? IEnumerator.Current => _current; void IEnumerator.Reset() { diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ThrowHelper.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ThrowHelper.cs index 8b8a0e4d37ce0c..66e8947ecad9d0 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ThrowHelper.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ThrowHelper.cs @@ -3,31 +3,37 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Primitives { internal static class ThrowHelper { + [DoesNotReturn] internal static void ThrowArgumentNullException(ExceptionArgument argument) { throw new ArgumentNullException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) { throw new ArgumentOutOfRangeException(GetArgumentName(argument)); } + [DoesNotReturn] internal static void ThrowArgumentException(ExceptionResource resource) { throw new ArgumentException(GetResourceText(resource)); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource) { throw new InvalidOperationException(GetResourceText(resource)); } + [DoesNotReturn] internal static void ThrowInvalidOperationException(ExceptionResource resource, params object[] args) { string message = string.Format(GetResourceText(resource), args); From 410613cb1f08383acc046cc3f2699e7905aa9ee6 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 13:13:09 +0300 Subject: [PATCH 02/21] StringValues array is non-nullable --- .../src/StringValues.cs | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 8c338b98a8ff3b..b7dd1c7eb3ef65 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Numerics.Hashing; using System.Runtime.CompilerServices; using System.Text; @@ -14,7 +15,7 @@ namespace Microsoft.Extensions.Primitives /// /// Represents zero/null, one, or many strings in an efficient way. /// - public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable + public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable { /// /// A readonly instance of the struct whose value is an empty string array. @@ -39,7 +40,7 @@ public StringValues(string? value) /// Initializes a new instance of the structure using the specified array of strings. /// /// A string array. - public StringValues(string[]? values) + public StringValues(string[] values) { _values = values; } @@ -57,7 +58,7 @@ public static implicit operator StringValues(string? value) /// Defines an implicit conversion of a given string array to a . /// /// A string array to implicitly convert. - public static implicit operator StringValues(string[]? values) + public static implicit operator StringValues(string[] values) { return new StringValues(values); } @@ -69,7 +70,7 @@ public static implicit operator StringValues(string[]? values) /// Returns null where has been initialized from an empty string array or is . /// /// A to implicitly convert. - public static implicit operator string?(StringValues values) + public static implicit operator string? (StringValues values) { return values.GetStringValue(); } @@ -78,7 +79,7 @@ public static implicit operator StringValues(string[]? values) /// Defines an implicit conversion of a given to a string array. /// /// A to implicitly convert. - public static implicit operator string[]?(StringValues value) + public static implicit operator string[]? (StringValues value) { return value.GetArrayValue(); } @@ -601,7 +602,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(string[]? left, StringValues right) => Equals(new StringValues(left), right); + public static bool Equals(string[] left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and string array objects have the same values. @@ -609,14 +610,22 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(StringValues left, string[]? right) => Equals(left, new StringValues(right)); + public static bool Equals(StringValues left, string[] right) => Equals(left, new StringValues(right)); /// /// Determines whether this instance and a specified string array have the same values. /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals(string[]? other) => Equals(this, new StringValues(other)); + public bool Equals(string[]? other) + { + if (other == null) + { + throw new ArgumentNullException(nameof(other)); + } + + return Equals(this, new StringValues(other)); + } /// public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); @@ -641,7 +650,7 @@ public static bool Equals(StringValues left, StringValues right) public static bool operator !=(string left, StringValues right) => !Equals(new StringValues(left), right); /// - public static bool operator ==(StringValues left, string[]? right) => Equals(left, new StringValues(right)); + public static bool operator ==(StringValues left, string[] right) => Equals(left, new StringValues(right)); /// /// Determines whether the specified and string array have different values. @@ -649,10 +658,10 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(StringValues left, string[]? right) => !Equals(left, new StringValues(right)); + public static bool operator !=(StringValues left, string[] right) => !Equals(left, new StringValues(right)); /// - public static bool operator ==(string[]? left, StringValues right) => Equals(new StringValues(left), right); + public static bool operator ==(string[] left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified string array and have different values. @@ -660,7 +669,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(string[]? left, StringValues right) => !Equals(new StringValues(left), right); + public static bool operator !=(string[] left, StringValues right) => !Equals(new StringValues(left), right); /// /// Determines whether the specified and , which must be a From 31b9391b7281dcbc1f87ed5404eb12445ae26a1f Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 13:15:05 +0300 Subject: [PATCH 03/21] Anotate ref --- .../ref/Microsoft.Extensions.Primitives.cs | 59 ++++++++++--------- .../Microsoft.Extensions.Primitives.csproj | 1 + 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index e591020d7a6800..ed9ba055c5a4c4 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -4,6 +4,8 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Primitives { public partial class CancellationChangeToken : Microsoft.Extensions.Primitives.IChangeToken @@ -11,7 +13,7 @@ public partial class CancellationChangeToken : Microsoft.Extensions.Primitives.I public CancellationChangeToken(System.Threading.CancellationToken cancellationToken) { } public bool ActiveChangeCallbacks { get { throw null; } } public bool HasChanged { get { throw null; } } - public System.IDisposable RegisterChangeCallback(System.Action callback, object state) { throw null; } + public System.IDisposable RegisterChangeCallback(System.Action callback, object? state) { throw null; } } public static partial class ChangeToken { @@ -24,7 +26,7 @@ public CompositeChangeToken(System.Collections.Generic.IReadOnlyList ChangeTokens { get { throw null; } } public bool HasChanged { get { throw null; } } - public System.IDisposable RegisterChangeCallback(System.Action callback, object state) { throw null; } + public System.IDisposable RegisterChangeCallback(System.Action callback, object? state) { throw null; } } public static partial class Extensions { @@ -34,7 +36,7 @@ public partial interface IChangeToken { bool ActiveChangeCallbacks { get; } bool HasChanged { get; } - System.IDisposable RegisterChangeCallback(System.Action callback, object state); + System.IDisposable RegisterChangeCallback(System.Action callback, object? state); } public readonly partial struct StringSegment : System.IEquatable, System.IEquatable { @@ -44,11 +46,12 @@ public partial interface IChangeToken public StringSegment(string buffer) { throw null; } public StringSegment(string buffer, int offset, int length) { throw null; } public string Buffer { get { throw null; } } + [MemberNotNullWhen(true, nameof(Buffer))] public bool HasValue { get { throw null; } } public char this[int index] { get { throw null; } } public int Length { get { throw null; } } public int Offset { get { throw null; } } - public string Value { get { throw null; } } + public string? Value { get { throw null; } } public System.ReadOnlyMemory AsMemory() { throw null; } public System.ReadOnlySpan AsSpan() { throw null; } public System.ReadOnlySpan AsSpan(int start) { throw null; } @@ -58,8 +61,8 @@ public partial interface IChangeToken public bool Equals(Microsoft.Extensions.Primitives.StringSegment other) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringSegment a, Microsoft.Extensions.Primitives.StringSegment b, System.StringComparison comparisonType) { throw null; } public bool Equals(Microsoft.Extensions.Primitives.StringSegment other, System.StringComparison comparisonType) { throw null; } - public override bool Equals(object obj) { throw null; } - public bool Equals(string text) { throw null; } + public override bool Equals(object? obj) { throw null; } + public bool Equals(string? text) { throw null; } public bool Equals(string text, System.StringComparison comparisonType) { throw null; } public override int GetHashCode() { throw null; } public int IndexOf(char c) { throw null; } @@ -71,9 +74,9 @@ public partial interface IChangeToken public static bool IsNullOrEmpty(Microsoft.Extensions.Primitives.StringSegment value) { throw null; } public int LastIndexOf(char value) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringSegment left, Microsoft.Extensions.Primitives.StringSegment right) { throw null; } - public static implicit operator System.ReadOnlyMemory (Microsoft.Extensions.Primitives.StringSegment segment) { throw null; } - public static implicit operator System.ReadOnlySpan (Microsoft.Extensions.Primitives.StringSegment segment) { throw null; } - public static implicit operator Microsoft.Extensions.Primitives.StringSegment (string value) { throw null; } + public static implicit operator System.ReadOnlyMemory(Microsoft.Extensions.Primitives.StringSegment segment) { throw null; } + public static implicit operator System.ReadOnlySpan(Microsoft.Extensions.Primitives.StringSegment segment) { throw null; } + public static implicit operator Microsoft.Extensions.Primitives.StringSegment(string value) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringSegment left, Microsoft.Extensions.Primitives.StringSegment right) { throw null; } public Microsoft.Extensions.Primitives.StringTokenizer Split(char[] chars) { throw null; } public bool StartsWith(string text, System.StringComparison comparisonType) { throw null; } @@ -116,49 +119,49 @@ public void Dispose() { } public void Reset() { } } } - public readonly partial struct StringValues : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.IEnumerable, System.IEquatable, System.IEquatable, System.IEquatable + public readonly partial struct StringValues : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.IEnumerable, System.IEquatable, System.IEquatable, System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; public static readonly Microsoft.Extensions.Primitives.StringValues Empty; - public StringValues(string value) { throw null; } + public StringValues(string? value) { throw null; } public StringValues(string[] values) { throw null; } public int Count { get { throw null; } } public string this[int index] { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } string System.Collections.Generic.IList.this[int index] { get { throw null; } set { } } public static Microsoft.Extensions.Primitives.StringValues Concat(Microsoft.Extensions.Primitives.StringValues values1, Microsoft.Extensions.Primitives.StringValues values2) { throw null; } - public static Microsoft.Extensions.Primitives.StringValues Concat(in Microsoft.Extensions.Primitives.StringValues values, string value) { throw null; } - public static Microsoft.Extensions.Primitives.StringValues Concat(string value, in Microsoft.Extensions.Primitives.StringValues values) { throw null; } + public static Microsoft.Extensions.Primitives.StringValues Concat(in Microsoft.Extensions.Primitives.StringValues values, string? value) { throw null; } + public static Microsoft.Extensions.Primitives.StringValues Concat(string? value, in Microsoft.Extensions.Primitives.StringValues values) { throw null; } public bool Equals(Microsoft.Extensions.Primitives.StringValues other) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string right) { throw null; } + public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } - public override bool Equals(object obj) { throw null; } - public bool Equals(string other) { throw null; } - public static bool Equals(string left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public bool Equals(string[] other) { throw null; } + public override bool Equals(object? obj) { throw null; } + public bool Equals(string? other) { throw null; } + public static bool Equals(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public bool Equals(string[]? other) { throw null; } public static bool Equals(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public Microsoft.Extensions.Primitives.StringValues.Enumerator GetEnumerator() { throw null; } public override int GetHashCode() { throw null; } public static bool IsNullOrEmpty(Microsoft.Extensions.Primitives.StringValues value) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, object right) { throw null; } - public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string right) { throw null; } + public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } public static bool operator ==(object left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator ==(string left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator ==(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator ==(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static implicit operator string (Microsoft.Extensions.Primitives.StringValues values) { throw null; } - public static implicit operator string[] (Microsoft.Extensions.Primitives.StringValues value) { throw null; } - public static implicit operator Microsoft.Extensions.Primitives.StringValues (string value) { throw null; } - public static implicit operator Microsoft.Extensions.Primitives.StringValues (string[] values) { throw null; } + public static implicit operator string?(Microsoft.Extensions.Primitives.StringValues values) { throw null; } + public static implicit operator string[](Microsoft.Extensions.Primitives.StringValues value) { throw null; } + public static implicit operator Microsoft.Extensions.Primitives.StringValues(string? value) { throw null; } + public static implicit operator Microsoft.Extensions.Primitives.StringValues(string[] values) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, object right) { throw null; } - public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string right) { throw null; } + public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } public static bool operator !=(object left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator !=(string left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator !=(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator !=(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } void System.Collections.Generic.ICollection.Add(string item) { } void System.Collections.Generic.ICollection.Clear() { } @@ -172,12 +175,12 @@ public void Reset() { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } public string[] ToArray() { throw null; } public override string ToString() { throw null; } - public partial struct Enumerator : System.Collections.Generic.IEnumerator, System.Collections.IEnumerator, System.IDisposable + public partial struct Enumerator : System.Collections.Generic.IEnumerator, System.Collections.IEnumerator, System.IDisposable { private object _dummy; private int _dummyPrimitive; public Enumerator(ref Microsoft.Extensions.Primitives.StringValues values) { throw null; } - public string Current { get { throw null; } } + public string? Current { get { throw null; } } object System.Collections.IEnumerator.Current { get { throw null; } } public void Dispose() { } public bool MoveNext() { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.csproj b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.csproj index e6f45298de118f..3c011149f76449 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.csproj +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent);netcoreapp3.1;netstandard2.0;net461 + enable From 27f43fb571a7848fa03dcab0fc41bff0396e3bb8 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 14:34:21 +0300 Subject: [PATCH 04/21] Fix analizer error --- .../Microsoft.Extensions.Primitives/src/StringValues.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index b7dd1c7eb3ef65..52ffbe0f715a9d 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -621,7 +621,7 @@ public bool Equals(string[]? other) { if (other == null) { - throw new ArgumentNullException(nameof(other)); + throw new ArgumentNullException(nameof(other)); } return Equals(this, new StringValues(other)); From 4be835adf4aa9a77c89f199a642ff586645ff350 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 15:32:53 +0300 Subject: [PATCH 05/21] Update Equals implementation --- .../src/StringValues.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 52ffbe0f715a9d..21dc75d9a6fe36 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -617,15 +617,7 @@ public static bool Equals(StringValues left, StringValues right) /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals(string[]? other) - { - if (other == null) - { - throw new ArgumentNullException(nameof(other)); - } - - return Equals(this, new StringValues(other)); - } + public bool Equals(string[]? other) => other != null && Equals(this, new StringValues(other)); /// public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); From e005156a79b955310f04a799f703dd73c7cd8482 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 15:53:13 +0300 Subject: [PATCH 06/21] Result of IChangeToken.RegisterChangeCallback is nullable --- .../ref/Microsoft.Extensions.Primitives.cs | 2 +- .../Microsoft.Extensions.Primitives/src/IChangeToken.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index ed9ba055c5a4c4..9cdfe02a6bf4dc 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -36,7 +36,7 @@ public partial interface IChangeToken { bool ActiveChangeCallbacks { get; } bool HasChanged { get; } - System.IDisposable RegisterChangeCallback(System.Action callback, object? state); + System.IDisposable? RegisterChangeCallback(System.Action callback, object? state); } public readonly partial struct StringSegment : System.IEquatable, System.IEquatable { diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs index f34122c21f723e..650e89ab784c44 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs @@ -28,6 +28,6 @@ public interface IChangeToken /// The to invoke. /// State to be passed into the callback. /// An that is used to unregister the callback. - IDisposable RegisterChangeCallback(Action callback, object? state); + IDisposable? RegisterChangeCallback(Action callback, object? state); } } From ec7558c90d2610ee1db6ef18c6bf40b7173f709b Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 16:12:56 +0300 Subject: [PATCH 07/21] Revert "Result of IChangeToken.RegisterChangeCallback is nullable" This reverts commit e005156a79b955310f04a799f703dd73c7cd8482. --- .../ref/Microsoft.Extensions.Primitives.cs | 2 +- .../Microsoft.Extensions.Primitives/src/IChangeToken.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index 9cdfe02a6bf4dc..ed9ba055c5a4c4 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -36,7 +36,7 @@ public partial interface IChangeToken { bool ActiveChangeCallbacks { get; } bool HasChanged { get; } - System.IDisposable? RegisterChangeCallback(System.Action callback, object? state); + System.IDisposable RegisterChangeCallback(System.Action callback, object? state); } public readonly partial struct StringSegment : System.IEquatable, System.IEquatable { diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs index 650e89ab784c44..f34122c21f723e 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/IChangeToken.cs @@ -28,6 +28,6 @@ public interface IChangeToken /// The to invoke. /// State to be passed into the callback. /// An that is used to unregister the callback. - IDisposable? RegisterChangeCallback(Action callback, object? state); + IDisposable RegisterChangeCallback(Action callback, object? state); } } From f81d799034c95460ddeb404830dea7101369f7a2 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 18:44:38 +0300 Subject: [PATCH 08/21] Dont use using in ref --- .../ref/Microsoft.Extensions.Primitives.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index ed9ba055c5a4c4..8b14120ae780ca 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -4,8 +4,6 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -using System.Diagnostics.CodeAnalysis; - namespace Microsoft.Extensions.Primitives { public partial class CancellationChangeToken : Microsoft.Extensions.Primitives.IChangeToken @@ -46,7 +44,7 @@ public partial interface IChangeToken public StringSegment(string buffer) { throw null; } public StringSegment(string buffer, int offset, int length) { throw null; } public string Buffer { get { throw null; } } - [MemberNotNullWhen(true, nameof(Buffer))] + [System.Diagnostics.CodeAnalysis.MemberNotNullWhen(true, nameof(Buffer))] public bool HasValue { get { throw null; } } public char this[int index] { get { throw null; } } public int Length { get { throw null; } } From d7230db614995656839c3601ae898813dac62528 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 20:42:21 +0300 Subject: [PATCH 09/21] Commit to rerun CI --- .../Microsoft.Extensions.Primitives/src/ChangeToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index 7e00d5f4ff3e52..e35df8562a16bf 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -141,7 +141,7 @@ private void SetDisposable(IDisposable disposable) public void Dispose() { // If the previous value is disposable then dispose it, otherwise, - // now we've set the disposed sentinel + // now we've set the disposed sentinel Interlocked.Exchange(ref _disposable, _disposedSentinel)?.Dispose(); } From ef4c639ceb6be56b42b5c37c64758f37957c08f5 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 20:42:32 +0300 Subject: [PATCH 10/21] Revert "Commit to rerun CI" This reverts commit d7230db614995656839c3601ae898813dac62528. --- .../Microsoft.Extensions.Primitives/src/ChangeToken.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index e35df8562a16bf..7e00d5f4ff3e52 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -141,7 +141,7 @@ private void SetDisposable(IDisposable disposable) public void Dispose() { // If the previous value is disposable then dispose it, otherwise, - // now we've set the disposed sentinel + // now we've set the disposed sentinel Interlocked.Exchange(ref _disposable, _disposedSentinel)?.Dispose(); } From d0b048973143e6fabd5a1087123589a20c964efc Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 21:41:09 +0300 Subject: [PATCH 11/21] StringValues can contain string?[] --- .../ref/Microsoft.Extensions.Primitives.cs | 56 ++++++------- .../src/StringValues.cs | 82 +++++++++---------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index 8b14120ae780ca..ece775785898cd 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -117,61 +117,61 @@ public void Dispose() { } public void Reset() { } } } - public readonly partial struct StringValues : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.IEnumerable, System.IEquatable, System.IEquatable, System.IEquatable + public readonly partial struct StringValues : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.IEnumerable, System.IEquatable, System.IEquatable, System.IEquatable { private readonly object _dummy; private readonly int _dummyPrimitive; public static readonly Microsoft.Extensions.Primitives.StringValues Empty; public StringValues(string? value) { throw null; } - public StringValues(string[] values) { throw null; } + public StringValues(string?[] values) { throw null; } public int Count { get { throw null; } } - public string this[int index] { get { throw null; } } - bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } - string System.Collections.Generic.IList.this[int index] { get { throw null; } set { } } + public string? this[int index] { get { throw null; } } + bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } + string? System.Collections.Generic.IList.this[int index] { get { throw null; } set { } } public static Microsoft.Extensions.Primitives.StringValues Concat(Microsoft.Extensions.Primitives.StringValues values1, Microsoft.Extensions.Primitives.StringValues values2) { throw null; } public static Microsoft.Extensions.Primitives.StringValues Concat(in Microsoft.Extensions.Primitives.StringValues values, string? value) { throw null; } public static Microsoft.Extensions.Primitives.StringValues Concat(string? value, in Microsoft.Extensions.Primitives.StringValues values) { throw null; } public bool Equals(Microsoft.Extensions.Primitives.StringValues other) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } + public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } public override bool Equals(object? obj) { throw null; } public bool Equals(string? other) { throw null; } public static bool Equals(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public bool Equals(string[]? other) { throw null; } - public static bool Equals(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public bool Equals(string?[]? other) { throw null; } + public static bool Equals(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public Microsoft.Extensions.Primitives.StringValues.Enumerator GetEnumerator() { throw null; } public override int GetHashCode() { throw null; } public static bool IsNullOrEmpty(Microsoft.Extensions.Primitives.StringValues value) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, object right) { throw null; } + public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, object? right) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } - public static bool operator ==(object left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } + public static bool operator ==(object? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator ==(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator ==(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator ==(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static implicit operator string?(Microsoft.Extensions.Primitives.StringValues values) { throw null; } - public static implicit operator string[](Microsoft.Extensions.Primitives.StringValues value) { throw null; } + public static implicit operator string?[](Microsoft.Extensions.Primitives.StringValues value) { throw null; } public static implicit operator Microsoft.Extensions.Primitives.StringValues(string? value) { throw null; } - public static implicit operator Microsoft.Extensions.Primitives.StringValues(string[] values) { throw null; } + public static implicit operator Microsoft.Extensions.Primitives.StringValues(string?[] values) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, object right) { throw null; } + public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, object? right) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string[] right) { throw null; } - public static bool operator !=(object left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } + public static bool operator !=(object? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator !=(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator !=(string[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - void System.Collections.Generic.ICollection.Add(string item) { } - void System.Collections.Generic.ICollection.Clear() { } - bool System.Collections.Generic.ICollection.Contains(string item) { throw null; } - void System.Collections.Generic.ICollection.CopyTo(string[] array, int arrayIndex) { } - bool System.Collections.Generic.ICollection.Remove(string item) { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.Generic.IList.IndexOf(string item) { throw null; } - void System.Collections.Generic.IList.Insert(int index, string item) { } - void System.Collections.Generic.IList.RemoveAt(int index) { } + public static bool operator !=(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + void System.Collections.Generic.ICollection.Add(string? item) { } + void System.Collections.Generic.ICollection.Clear() { } + bool System.Collections.Generic.ICollection.Contains(string? item) { throw null; } + void System.Collections.Generic.ICollection.CopyTo(string?[] array, int arrayIndex) { } + bool System.Collections.Generic.ICollection.Remove(string? item) { throw null; } + System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } + int System.Collections.Generic.IList.IndexOf(string? item) { throw null; } + void System.Collections.Generic.IList.Insert(int index, string? item) { } + void System.Collections.Generic.IList.RemoveAt(int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - public string[] ToArray() { throw null; } + public string?[] ToArray() { throw null; } public override string ToString() { throw null; } public partial struct Enumerator : System.Collections.Generic.IEnumerator, System.Collections.IEnumerator, System.IDisposable { diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 21dc75d9a6fe36..669d4268fd1a8c 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -15,7 +15,7 @@ namespace Microsoft.Extensions.Primitives /// /// Represents zero/null, one, or many strings in an efficient way. /// - public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable + public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable { /// /// A readonly instance of the struct whose value is an empty string array. @@ -40,7 +40,7 @@ public StringValues(string? value) /// Initializes a new instance of the structure using the specified array of strings. /// /// A string array. - public StringValues(string[] values) + public StringValues(string?[] values) { _values = values; } @@ -58,7 +58,7 @@ public static implicit operator StringValues(string? value) /// Defines an implicit conversion of a given string array to a . /// /// A string array to implicitly convert. - public static implicit operator StringValues(string[] values) + public static implicit operator StringValues(string?[] values) { return new StringValues(values); } @@ -79,7 +79,7 @@ public static implicit operator StringValues(string[] values) /// Defines an implicit conversion of a given to a string array. /// /// A to implicitly convert. - public static implicit operator string[]? (StringValues value) + public static implicit operator string?[]? (StringValues value) { return value.GetArrayValue(); } @@ -105,12 +105,12 @@ public int Count else { // Not string, not null, can only be string[] - return Unsafe.As(value).Length; + return Unsafe.As(value).Length; } } } - bool ICollection.IsReadOnly => true; + bool ICollection.IsReadOnly => true; /// /// Gets the at index. @@ -118,7 +118,7 @@ public int Count /// The string at the specified index. /// The zero-based index of the element to get. /// Set operations are not supported on readonly . - string IList.this[int index] + string? IList.this[int index] { get => this[index]; set => throw new NotSupportedException(); @@ -129,7 +129,7 @@ string IList.this[int index] /// /// The string at the specified index. /// The zero-based index of the element to get. - public string this[int index] + public string? this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get @@ -146,7 +146,7 @@ public string this[int index] else if (value != null) { // Not string, not null, can only be string[] - return Unsafe.As(value)[index]; // may throw + return Unsafe.As(value)[index]; // may throw } return OutOfBounds(); // throws @@ -190,7 +190,7 @@ public override string ToString() Debug.Assert(value is string[]); // value is not null or string, array, can only be string[] - string[] values = Unsafe.As(value); + string?[] values = Unsafe.As(value); return values.Length switch { 0 => null, @@ -199,13 +199,13 @@ public override string ToString() }; } - static string GetJoinedStringValueFromArray(string[] values) + static string GetJoinedStringValueFromArray(string?[] values) { // Calculate final length int length = 0; for (int i = 0; i < values.Length; i++) { - string value = values[i]; + string? value = values[i]; // Skip null and empty values if (value != null && value.Length > 0) { @@ -225,7 +225,7 @@ static string GetJoinedStringValueFromArray(string[] values) // Skip null and empty values for (int i = 0; i < strings.Length; i++) { - string value = strings[i]; + string? value = strings[i]; if (value != null && value.Length > 0) { if (offset > 0) @@ -246,7 +246,7 @@ static string GetJoinedStringValueFromArray(string[] values) // Skip null and empty values for (int i = 0; i < values.Length; i++) { - string value = values[i]; + string? value = values[i]; if (value != null && value.Length > 0) { if (hasAdded) @@ -273,12 +273,12 @@ static string GetJoinedStringValueFromArray(string[] values) /// If the contains a single string internally, it is copied to a new array. /// If the contains an array internally it returns that array instance. /// - public string[] ToArray() + public string?[] ToArray() { return GetArrayValue() ?? Array.Empty(); } - private string[]? GetArrayValue() + private string?[]? GetArrayValue() { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory object? value = _values; @@ -302,12 +302,12 @@ public string[] ToArray() /// /// The string to locate in the . /// the zero-based index of the first occurrence of within the , if found; otherwise, -1. - int IList.IndexOf(string item) + int IList.IndexOf(string? item) { return IndexOf(item); } - private int IndexOf(string item) + private int IndexOf(string? item) { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory object? value = _values; @@ -335,7 +335,7 @@ private int IndexOf(string item) /// Determines whether a string is in the . /// The to locate in the . /// true if item is found in the ; otherwise, false. - bool ICollection.Contains(string item) + bool ICollection.Contains(string? item) { return IndexOf(item) >= 0; } @@ -348,12 +348,12 @@ bool ICollection.Contains(string item) /// array is null. /// arrayIndex is less than 0. /// The number of elements in the source is greater than the available space from arrayIndex to the end of the destination array. - void ICollection.CopyTo(string[] array, int arrayIndex) + void ICollection.CopyTo(string?[] array, int arrayIndex) { CopyTo(array, arrayIndex); } - private void CopyTo(string[] array, int arrayIndex) + private void CopyTo(string?[] array, int arrayIndex) { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory object? value = _values; @@ -384,15 +384,15 @@ private void CopyTo(string[] array, int arrayIndex) } } - void ICollection.Add(string item) => throw new NotSupportedException(); + void ICollection.Add(string? item) => throw new NotSupportedException(); - void IList.Insert(int index, string item) => throw new NotSupportedException(); + void IList.Insert(int index, string? item) => throw new NotSupportedException(); - bool ICollection.Remove(string item) => throw new NotSupportedException(); + bool ICollection.Remove(string? item) => throw new NotSupportedException(); - void IList.RemoveAt(int index) => throw new NotSupportedException(); + void IList.RemoveAt(int index) => throw new NotSupportedException(); - void ICollection.Clear() => throw new NotSupportedException(); + void ICollection.Clear() => throw new NotSupportedException(); /// Retrieves an object that can iterate through the individual strings in this . /// An enumerator that can be used to iterate through the . @@ -402,7 +402,7 @@ public Enumerator GetEnumerator() } /// - IEnumerator IEnumerable.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } @@ -602,7 +602,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(string[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool Equals(string?[] left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and string array objects have the same values. @@ -610,14 +610,14 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(StringValues left, string[] right) => Equals(left, new StringValues(right)); + public static bool Equals(StringValues left, string?[] right) => Equals(left, new StringValues(right)); /// /// Determines whether this instance and a specified string array have the same values. /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals(string[]? other) => other != null && Equals(this, new StringValues(other)); + public bool Equals(string?[]? other) => other != null && Equals(this, new StringValues(other)); /// public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); @@ -642,7 +642,7 @@ public static bool Equals(StringValues left, StringValues right) public static bool operator !=(string left, StringValues right) => !Equals(new StringValues(left), right); /// - public static bool operator ==(StringValues left, string[] right) => Equals(left, new StringValues(right)); + public static bool operator ==(StringValues left, string?[] right) => Equals(left, new StringValues(right)); /// /// Determines whether the specified and string array have different values. @@ -650,10 +650,10 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(StringValues left, string[] right) => !Equals(left, new StringValues(right)); + public static bool operator !=(StringValues left, string?[] right) => !Equals(left, new StringValues(right)); /// - public static bool operator ==(string[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool operator ==(string?[] left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified string array and have different values. @@ -661,7 +661,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(string[] left, StringValues right) => !Equals(new StringValues(left), right); + public static bool operator !=(string?[] left, StringValues right) => !Equals(new StringValues(left), right); /// /// Determines whether the specified and , which must be a @@ -670,7 +670,7 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the object is equal to the ; otherwise, false. - public static bool operator ==(StringValues left, object right) => left.Equals(right); + public static bool operator ==(StringValues left, object? right) => left.Equals(right); /// /// Determines whether the specified and , which must be a @@ -679,7 +679,7 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the object is equal to the ; otherwise, false. - public static bool operator !=(StringValues left, object right) => !left.Equals(right); + public static bool operator !=(StringValues left, object? right) => !left.Equals(right); /// /// Determines whether the specified , which must be a @@ -688,7 +688,7 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the object is equal to the ; otherwise, false. - public static bool operator ==(object left, StringValues right) => right.Equals(left); + public static bool operator ==(object? left, StringValues right) => right.Equals(left); /// /// Determines whether the specified and object have the same values. @@ -696,7 +696,7 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The to compare. /// true if the object is equal to the ; otherwise, false. - public static bool operator !=(object left, StringValues right) => !right.Equals(left); + public static bool operator !=(object? left, StringValues right) => !right.Equals(left); /// /// Determines whether this instance and a specified object have the same value. @@ -756,7 +756,7 @@ public override int GetHashCode() /// public struct Enumerator : IEnumerator { - private readonly string[]? _values; + private readonly string?[]? _values; private int _index; private string? _current; @@ -770,7 +770,7 @@ internal Enumerator(object? value) else { _current = null; - _values = Unsafe.As(value); + _values = Unsafe.As(value); } _index = 0; } @@ -786,7 +786,7 @@ public bool MoveNext() return false; } - string[]? values = _values; + string?[]? values = _values; if (values != null) { if ((uint)index < (uint)values.Length) From 6b1fed815e034ee390f70a70ab0f2c5409488a53 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sat, 14 Aug 2021 21:57:03 +0300 Subject: [PATCH 12/21] Equals [NotNullWhen(true)] --- .../ref/Microsoft.Extensions.Primitives.cs | 4 ++-- .../Microsoft.Extensions.Primitives/src/StringSegment.cs | 2 +- .../Microsoft.Extensions.Primitives/src/StringValues.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index ece775785898cd..505fc50d6dbbb4 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -59,7 +59,7 @@ public partial interface IChangeToken public bool Equals(Microsoft.Extensions.Primitives.StringSegment other) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringSegment a, Microsoft.Extensions.Primitives.StringSegment b, System.StringComparison comparisonType) { throw null; } public bool Equals(Microsoft.Extensions.Primitives.StringSegment other, System.StringComparison comparisonType) { throw null; } - public override bool Equals(object? obj) { throw null; } + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? obj) { throw null; } public bool Equals(string? text) { throw null; } public bool Equals(string text, System.StringComparison comparisonType) { throw null; } public override int GetHashCode() { throw null; } @@ -138,7 +138,7 @@ public void Reset() { } public override bool Equals(object? obj) { throw null; } public bool Equals(string? other) { throw null; } public static bool Equals(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public bool Equals(string?[]? other) { throw null; } + public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string?[]? other) { throw null; } public static bool Equals(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public Microsoft.Extensions.Primitives.StringValues.Enumerator GetEnumerator() { throw null; } public override int GetHashCode() { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs index 4b73f1ff2dad6d..faca83caedcaf5 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs @@ -190,7 +190,7 @@ public static int Compare(StringSegment a, StringSegment b, StringComparison com /// /// An object to compare with this object. /// if the current object is equal to the other parameter; otherwise, . - public override bool Equals(object? obj) + public override bool Equals([NotNullWhen(true)] object? obj) { return obj is StringSegment segment && Equals(segment); } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 669d4268fd1a8c..a00d5effce49b1 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -617,7 +617,7 @@ public static bool Equals(StringValues left, StringValues right) /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals(string?[]? other) => other != null && Equals(this, new StringValues(other)); + public bool Equals([NotNullWhen(true)] string?[]? other) => other != null && Equals(this, new StringValues(other)); /// public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); From d6010db4de63cbcb07d35bd42c4b1072940e167d Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sun, 15 Aug 2021 04:06:10 +0300 Subject: [PATCH 13/21] text = null - retrun false --- .../ref/Microsoft.Extensions.Primitives.cs | 4 ++-- .../Microsoft.Extensions.Primitives/src/StringSegment.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index 505fc50d6dbbb4..2802f7f0994643 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -60,8 +60,8 @@ public partial interface IChangeToken public static bool Equals(Microsoft.Extensions.Primitives.StringSegment a, Microsoft.Extensions.Primitives.StringSegment b, System.StringComparison comparisonType) { throw null; } public bool Equals(Microsoft.Extensions.Primitives.StringSegment other, System.StringComparison comparisonType) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] object? obj) { throw null; } - public bool Equals(string? text) { throw null; } - public bool Equals(string text, System.StringComparison comparisonType) { throw null; } + public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? text) { throw null; } + public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? text, System.StringComparison comparisonType) { throw null; } public override int GetHashCode() { throw null; } public int IndexOf(char c) { throw null; } public int IndexOf(char c, int start) { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs index faca83caedcaf5..68d757c5b44782 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs @@ -241,7 +241,7 @@ public static bool Equals(StringSegment a, StringSegment b, StringComparison com /// /// The to compare with the current . /// if the specified is equal to the current ; otherwise, . - public bool Equals(string text) + public bool Equals([NotNullWhen(true)] string? text) { return Equals(text, StringComparison.Ordinal); } @@ -256,11 +256,11 @@ public bool Equals(string text) /// is . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(string text, StringComparison comparisonType) + public bool Equals([NotNullWhen(true)] string? text, StringComparison comparisonType) { if (text == null) { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text); + return false; } if (!HasValue) From 376a112ea7c01cafa9bfb38eab3fc27e8ae3f9ae Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Sun, 15 Aug 2021 04:56:24 +0300 Subject: [PATCH 14/21] text = null - retrun false (tests) --- .../tests/StringSegmentTest.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/tests/StringSegmentTest.cs b/src/libraries/Microsoft.Extensions.Primitives/tests/StringSegmentTest.cs index aea63a8df70b23..812a154e3bfc93 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/tests/StringSegmentTest.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/tests/StringSegmentTest.cs @@ -462,6 +462,8 @@ public static TheoryData EqualsStringData { { "eLLo", StringComparison.OrdinalIgnoreCase, true }, { "eLLo", StringComparison.Ordinal, false }, + { null, StringComparison.OrdinalIgnoreCase, false }, + { null, StringComparison.Ordinal, false }, }; } } @@ -480,17 +482,6 @@ public void StringSegment_Equals_String_Valid(string candidate, StringComparison Assert.Equal(expectedResult, result); } - [Fact] - public void StringSegment_Equals_NullString_Throws() - { - // Arrange - var segment = new StringSegment(); - - // Act & assert - Assert.Throws("text", () => segment.Equals((string)null)); - Assert.Throws("text", () => segment.Equals((string)null, StringComparison.Ordinal)); - } - [Fact] public void StringSegment_Equals_String_InvalidComparisonType_Throws() { From ee3987941b23161df2f1547e5357bd7f536b62e6 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Mon, 16 Aug 2021 23:20:11 +0300 Subject: [PATCH 15/21] Remove unneeded ?. --- .../Microsoft.Extensions.Primitives/src/ChangeToken.cs | 4 ++-- .../src/CompositeChangeToken.cs | 6 ++++-- .../Microsoft.Extensions.Primitives/src/StringTokenizer.cs | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index 7e00d5f4ff3e52..47801674f4df37 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -100,7 +100,7 @@ private void RegisterChangeTokenCallback(IChangeToken token) return; } - IDisposable registraton = token.RegisterChangeCallback(s => ((ChangeTokenRegistration?)s)?.OnChangeTokenFired(), this); + IDisposable registraton = token.RegisterChangeCallback(s => ((ChangeTokenRegistration?)s)!.OnChangeTokenFired(), this); SetDisposable(registraton); } @@ -142,7 +142,7 @@ public void Dispose() { // If the previous value is disposable then dispose it, otherwise, // now we've set the disposed sentinel - Interlocked.Exchange(ref _disposable, _disposedSentinel)?.Dispose(); + Interlocked.Exchange(ref _disposable, _disposedSentinel)!.Dispose(); } private sealed class NoopDisposable : IDisposable diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs index 66eb544cf47895..d64982f0f562df 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs @@ -110,8 +110,10 @@ private void EnsureCallbacksInitialized() private static void OnChange(object? state) { - var compositeChangeTokenState = (CompositeChangeToken?)state; - if (compositeChangeTokenState?._cancellationTokenSource == null) + Debug.Assert(state != null); + + var compositeChangeTokenState = (CompositeChangeToken)state; + if (compositeChangeTokenState._cancellationTokenSource == null) { return; } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs index 869ab54a5b1a7c..d3571852574761 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringTokenizer.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections; using System.Collections.Generic; From 9a98d03c32d3f971b687859d341c616051cac975 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Mon, 16 Aug 2021 23:22:18 +0300 Subject: [PATCH 16/21] IChangeToken can be null --- .../ref/Microsoft.Extensions.Primitives.cs | 4 ++-- .../src/ChangeToken.cs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index 2802f7f0994643..af2893c5980f24 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -15,8 +15,8 @@ public CancellationChangeToken(System.Threading.CancellationToken cancellationTo } public static partial class ChangeToken { - public static System.IDisposable OnChange(System.Func changeTokenProducer, System.Action changeTokenConsumer) { throw null; } - public static System.IDisposable OnChange(System.Func changeTokenProducer, System.Action changeTokenConsumer, TState state) { throw null; } + public static System.IDisposable OnChange(System.Func changeTokenProducer, System.Action changeTokenConsumer) { throw null; } + public static System.IDisposable OnChange(System.Func changeTokenProducer, System.Action changeTokenConsumer, TState state) { throw null; } } public partial class CompositeChangeToken : Microsoft.Extensions.Primitives.IChangeToken { diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index 47801674f4df37..0fc003520b88db 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -18,7 +18,7 @@ public static class ChangeToken /// Produces the change token. /// Action called when the token changes. /// - public static IDisposable OnChange(Func changeTokenProducer, Action changeTokenConsumer) + public static IDisposable OnChange(Func changeTokenProducer, Action changeTokenConsumer) { if (changeTokenProducer == null) { @@ -39,7 +39,7 @@ public static IDisposable OnChange(Func changeTokenProducer, Actio /// Action called when the token changes. /// state for the consumer. /// - public static IDisposable OnChange(Func changeTokenProducer, Action changeTokenConsumer, TState state) + public static IDisposable OnChange(Func changeTokenProducer, Action changeTokenConsumer, TState state) { if (changeTokenProducer == null) { @@ -55,20 +55,20 @@ public static IDisposable OnChange(Func changeTokenProduce private sealed class ChangeTokenRegistration : IDisposable { - private readonly Func _changeTokenProducer; + private readonly Func _changeTokenProducer; private readonly Action _changeTokenConsumer; private readonly TState _state; private IDisposable? _disposable; private static readonly NoopDisposable _disposedSentinel = new NoopDisposable(); - public ChangeTokenRegistration(Func changeTokenProducer, Action changeTokenConsumer, TState state) + public ChangeTokenRegistration(Func changeTokenProducer, Action changeTokenConsumer, TState state) { _changeTokenProducer = changeTokenProducer; _changeTokenConsumer = changeTokenConsumer; _state = state; - IChangeToken token = changeTokenProducer(); + IChangeToken? token = changeTokenProducer(); RegisterChangeTokenCallback(token); } @@ -80,7 +80,7 @@ private void OnChangeTokenFired() // // If the token changes after we take the token, then we'll process the update immediately upon // registering the callback. - IChangeToken token = _changeTokenProducer(); + IChangeToken? token = _changeTokenProducer(); try { @@ -93,7 +93,7 @@ private void OnChangeTokenFired() } } - private void RegisterChangeTokenCallback(IChangeToken token) + private void RegisterChangeTokenCallback(IChangeToken? token) { if (token is null) { From 4dc5fa76978b8345e98c29aa7d977c6c1eacc4fc Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Tue, 17 Aug 2021 10:35:33 +0300 Subject: [PATCH 17/21] Update doc --- .../Microsoft.Extensions.Primitives/src/StringSegment.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs index 68d757c5b44782..ef7c4df3909e79 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringSegment.cs @@ -252,9 +252,6 @@ public bool Equals([NotNullWhen(true)] string? text) /// The to compare with the current . /// One of the enumeration values that specifies the rules to use in the comparison. /// if the specified is equal to the current ; otherwise, . - /// - /// is . - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals([NotNullWhen(true)] string? text, StringComparison comparisonType) { From 49ad673d266eb2db921cf242d6009d0ab1492a78 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Tue, 17 Aug 2021 10:42:24 +0300 Subject: [PATCH 18/21] NullTokenDisposeShouldNotThrow --- .../Microsoft.Extensions.Primitives/src/ChangeToken.cs | 2 +- .../tests/ChangeTokenTest.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs index 0fc003520b88db..d0ddc8b8143f3b 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/ChangeToken.cs @@ -142,7 +142,7 @@ public void Dispose() { // If the previous value is disposable then dispose it, otherwise, // now we've set the disposed sentinel - Interlocked.Exchange(ref _disposable, _disposedSentinel)!.Dispose(); + Interlocked.Exchange(ref _disposable, _disposedSentinel)?.Dispose(); } private sealed class NoopDisposable : IDisposable diff --git a/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs b/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs index 05c2df370959b7..5c47eb72480285 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using Xunit; @@ -234,6 +235,12 @@ public void DoubleDisposeDisposesOnce() Assert.Equal(2, provider.DisposeCalls); } + [Fact] + public void NullTokenDisposeShouldNotThrow() + { + ChangeToken.OnChange(() => null, () => Debug.Fail("Should never be called")).Dispose(); + } + public class TrackableChangeTokenProvider { private TrackableChangeToken _cts = new TrackableChangeToken(); From f648dc4e96e8116c791bf4b4dd644d5f66d5272d Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Tue, 17 Aug 2021 16:36:07 +0300 Subject: [PATCH 19/21] _registeredCallbackProxy -> RegisteredCallbackProxy --- .../src/CompositeChangeToken.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs index d64982f0f562df..7df86773f7d728 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/CompositeChangeToken.cs @@ -21,7 +21,7 @@ public class CompositeChangeToken : IChangeToken [MemberNotNullWhen(true, nameof(_cancellationTokenSource))] [MemberNotNullWhen(true, nameof(_disposables))] - private bool _registeredCallbackProxy { get; set; } + private bool RegisteredCallbackProxy { get; set; } /// /// Creates a new instance of . @@ -82,14 +82,14 @@ public bool HasChanged [MemberNotNull(nameof(_disposables))] private void EnsureCallbacksInitialized() { - if (_registeredCallbackProxy) + if (RegisteredCallbackProxy) { return; } lock (_callbackLock) { - if (_registeredCallbackProxy) + if (RegisteredCallbackProxy) { return; } @@ -104,7 +104,7 @@ private void EnsureCallbacksInitialized() _disposables.Add(disposable); } } - _registeredCallbackProxy = true; + RegisteredCallbackProxy = true; } } From 1748ecc2b2b53a78933d8fa93d891676b7d15840 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Tue, 17 Aug 2021 18:46:10 +0300 Subject: [PATCH 20/21] StringValues can be created from string?[]? --- .../ref/Microsoft.Extensions.Primitives.cs | 20 +++++++++--------- .../src/StringValues.cs | 21 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs index af2893c5980f24..d9ba35bb4daf65 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/ref/Microsoft.Extensions.Primitives.cs @@ -123,7 +123,7 @@ public void Reset() { } private readonly int _dummyPrimitive; public static readonly Microsoft.Extensions.Primitives.StringValues Empty; public StringValues(string? value) { throw null; } - public StringValues(string?[] values) { throw null; } + public StringValues(string?[]? values) { throw null; } public int Count { get { throw null; } } public string? this[int index] { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } @@ -134,33 +134,33 @@ public void Reset() { } public bool Equals(Microsoft.Extensions.Primitives.StringValues other) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } + public static bool Equals(Microsoft.Extensions.Primitives.StringValues left, string?[]? right) { throw null; } public override bool Equals(object? obj) { throw null; } public bool Equals(string? other) { throw null; } public static bool Equals(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string?[]? other) { throw null; } - public static bool Equals(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public bool Equals(string?[]? other) { throw null; } + public static bool Equals(string?[]? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public Microsoft.Extensions.Primitives.StringValues.Enumerator GetEnumerator() { throw null; } public override int GetHashCode() { throw null; } public static bool IsNullOrEmpty(Microsoft.Extensions.Primitives.StringValues value) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, object? right) { throw null; } public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } + public static bool operator ==(Microsoft.Extensions.Primitives.StringValues left, string?[]? right) { throw null; } public static bool operator ==(object? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator ==(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator ==(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator ==(string?[]? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static implicit operator string?(Microsoft.Extensions.Primitives.StringValues values) { throw null; } - public static implicit operator string?[](Microsoft.Extensions.Primitives.StringValues value) { throw null; } + public static implicit operator string?[]?(Microsoft.Extensions.Primitives.StringValues value) { throw null; } public static implicit operator Microsoft.Extensions.Primitives.StringValues(string? value) { throw null; } - public static implicit operator Microsoft.Extensions.Primitives.StringValues(string?[] values) { throw null; } + public static implicit operator Microsoft.Extensions.Primitives.StringValues(string?[]? values) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, object? right) { throw null; } public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string? right) { throw null; } - public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string?[] right) { throw null; } + public static bool operator !=(Microsoft.Extensions.Primitives.StringValues left, string?[]? right) { throw null; } public static bool operator !=(object? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } public static bool operator !=(string? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } - public static bool operator !=(string?[] left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } + public static bool operator !=(string?[]? left, Microsoft.Extensions.Primitives.StringValues right) { throw null; } void System.Collections.Generic.ICollection.Add(string? item) { } void System.Collections.Generic.ICollection.Clear() { } bool System.Collections.Generic.ICollection.Contains(string? item) { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index a00d5effce49b1..029b6922965fd4 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Numerics.Hashing; using System.Runtime.CompilerServices; using System.Text; @@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Primitives /// /// Represents zero/null, one, or many strings in an efficient way. /// - public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable + public readonly struct StringValues : IList, IReadOnlyList, IEquatable, IEquatable, IEquatable { /// /// A readonly instance of the struct whose value is an empty string array. @@ -40,7 +39,7 @@ public StringValues(string? value) /// Initializes a new instance of the structure using the specified array of strings. /// /// A string array. - public StringValues(string?[] values) + public StringValues(string?[]? values) { _values = values; } @@ -58,7 +57,7 @@ public static implicit operator StringValues(string? value) /// Defines an implicit conversion of a given string array to a . /// /// A string array to implicitly convert. - public static implicit operator StringValues(string?[] values) + public static implicit operator StringValues(string?[]? values) { return new StringValues(values); } @@ -602,7 +601,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(string?[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool Equals(string?[]? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified and string array objects have the same values. @@ -610,14 +609,14 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is the same as the value of ; otherwise, false. - public static bool Equals(StringValues left, string?[] right) => Equals(left, new StringValues(right)); + public static bool Equals(StringValues left, string?[]? right) => Equals(left, new StringValues(right)); /// /// Determines whether this instance and a specified string array have the same values. /// /// The string array to compare to this instance. /// true if the value of is the same as this instance; otherwise, false. - public bool Equals([NotNullWhen(true)] string?[]? other) => other != null && Equals(this, new StringValues(other)); + public bool Equals(string?[]? other) => Equals(this, new StringValues(other)); /// public static bool operator ==(StringValues left, string? right) => Equals(left, new StringValues(right)); @@ -642,7 +641,7 @@ public static bool Equals(StringValues left, StringValues right) public static bool operator !=(string left, StringValues right) => !Equals(new StringValues(left), right); /// - public static bool operator ==(StringValues left, string?[] right) => Equals(left, new StringValues(right)); + public static bool operator ==(StringValues left, string?[]? right) => Equals(left, new StringValues(right)); /// /// Determines whether the specified and string array have different values. @@ -650,10 +649,10 @@ public static bool Equals(StringValues left, StringValues right) /// The to compare. /// The string array to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(StringValues left, string?[] right) => !Equals(left, new StringValues(right)); + public static bool operator !=(StringValues left, string?[]? right) => !Equals(left, new StringValues(right)); /// - public static bool operator ==(string?[] left, StringValues right) => Equals(new StringValues(left), right); + public static bool operator ==(string?[]? left, StringValues right) => Equals(new StringValues(left), right); /// /// Determines whether the specified string array and have different values. @@ -661,7 +660,7 @@ public static bool Equals(StringValues left, StringValues right) /// The string array to compare. /// The to compare. /// true if the value of is different to the value of ; otherwise, false. - public static bool operator !=(string?[] left, StringValues right) => !Equals(new StringValues(left), right); + public static bool operator !=(string?[]? left, StringValues right) => !Equals(new StringValues(left), right); /// /// Determines whether the specified and , which must be a From 80079fd2032ed915b5a7984a1eb8ac9c12d833f5 Mon Sep 17 00:00:00 2001 From: Maksym Koshovyi Date: Tue, 17 Aug 2021 18:47:18 +0300 Subject: [PATCH 21/21] Debug.Fail -> Assert.True(false) --- .../Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs b/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs index 5c47eb72480285..6cebf8a8138069 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/tests/ChangeTokenTest.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Threading; using Xunit; @@ -238,7 +236,7 @@ public void DoubleDisposeDisposesOnce() [Fact] public void NullTokenDisposeShouldNotThrow() { - ChangeToken.OnChange(() => null, () => Debug.Fail("Should never be called")).Dispose(); + ChangeToken.OnChange(() => null, () => Assert.True(false)).Dispose(); } public class TrackableChangeTokenProvider