diff --git a/Ix.NET/Source/Benchmarks.System.Interactive/BufferCountBenchmark.cs b/Ix.NET/Source/Benchmarks.System.Interactive/BufferCountBenchmark.cs index 81ee6ca4d9..149b151625 100644 --- a/Ix.NET/Source/Benchmarks.System.Interactive/BufferCountBenchmark.cs +++ b/Ix.NET/Source/Benchmarks.System.Interactive/BufferCountBenchmark.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -15,7 +14,7 @@ public class BufferCountBenchmark { [Params(1, 10, 100, 1000, 10000, 100000, 1000000)] public int N; - private IList _store; + private IList? _store; [Benchmark] public void Exact() diff --git a/Ix.NET/Source/Benchmarks.System.Interactive/IgnoreElementsBenchmark.cs b/Ix.NET/Source/Benchmarks.System.Interactive/IgnoreElementsBenchmark.cs index 272424807b..5babc4c446 100644 --- a/Ix.NET/Source/Benchmarks.System.Interactive/IgnoreElementsBenchmark.cs +++ b/Ix.NET/Source/Benchmarks.System.Interactive/IgnoreElementsBenchmark.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -18,8 +17,8 @@ public class IgnoreElementsBenchmark private int _store; - private int[] _array; - private List _list; + private int[]? _array; + private List? _list; [Benchmark] public void Ignore() @@ -32,7 +31,7 @@ public void Ignore() [Benchmark] public void IgnoreList() { - _list + _list! .IgnoreElements() .Subscribe(v => Volatile.Write(ref _store, v)); } @@ -40,7 +39,7 @@ public void IgnoreList() [Benchmark] public void IgnoreArray() { - _array + _array! .IgnoreElements() .Subscribe(v => Volatile.Write(ref _store, v)); } diff --git a/Ix.NET/Source/Benchmarks.System.Interactive/MinMaxBenchmark.cs b/Ix.NET/Source/Benchmarks.System.Interactive/MinMaxBenchmark.cs index 24a95cc56b..16306c7034 100644 --- a/Ix.NET/Source/Benchmarks.System.Interactive/MinMaxBenchmark.cs +++ b/Ix.NET/Source/Benchmarks.System.Interactive/MinMaxBenchmark.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -16,7 +15,7 @@ public class MinMaxBenchmark [Params(1, 10, 100, 1000, 10000, 100000, 1000000)] public int N; private int _store; - private IList _listStore; + private IList? _listStore; private readonly IComparer _comparer = Comparer.Default; diff --git a/Ix.NET/Source/System.Interactive.Providers/System/Linq/QueryableEx.cs b/Ix.NET/Source/System.Interactive.Providers/System/Linq/QueryableEx.cs index e9cdbc678b..cee0bae97c 100644 --- a/Ix.NET/Source/System.Interactive.Providers/System/Linq/QueryableEx.cs +++ b/Ix.NET/Source/System.Interactive.Providers/System/Linq/QueryableEx.cs @@ -100,7 +100,7 @@ private static ILookup GetMethods(Type type) return type.GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name); } - private static bool ArgsMatch(MethodInfo method, IList arguments, Type[] typeArgs) + private static bool ArgsMatch(MethodInfo method, IList arguments, Type[]? typeArgs) { // // Number of parameters should match. Notice we've sanitized IQueryProvider "this" diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs b/Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs index ffdac09cb8..7b8ba4b9ec 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Operators/DistinctUntilChanged.cs @@ -80,7 +80,7 @@ public static IEnumerable DistinctUntilChanged(this IEnu private static IEnumerable DistinctUntilChangedCore(IEnumerable source, Func keySelector, IEqualityComparer comparer) { - var currentKey = default(TKey); + var currentKey = default(TKey)!; var hasCurrentKey = false; foreach (var item in source) diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs index 843e4d9fbe..64d3ba67fd 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Memoize.cs @@ -113,10 +113,12 @@ public static IEnumerable Memoize(this IEnumerable : IBuffer { - private IRefCountList _buffer; + private readonly object _gate = new object(); + private readonly IRefCountList _buffer; + private readonly IEnumerator _source; + private bool _disposed; private Exception? _error; - private IEnumerator _source; private bool _stopped; public MemoizedBuffer(IEnumerator source) @@ -153,15 +155,12 @@ IEnumerator IEnumerable.GetEnumerator() public void Dispose() { - lock (_source) + lock (_gate) { if (!_disposed) { _source.Dispose(); - _source = null; - _buffer.Clear(); - _buffer = null; } _disposed = true; @@ -180,9 +179,9 @@ private IEnumerator GetEnumerator_() throw new ObjectDisposedException(""); var hasValue = default(bool); - var current = default(T); + var current = default(T)!; - lock (_source) + lock (_gate) { if (i >= _buffer.Count) { diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Operators/OnErrorResumeNext.cs b/Ix.NET/Source/System.Interactive/System/Linq/Operators/OnErrorResumeNext.cs index 6872d0a570..235b70545a 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Operators/OnErrorResumeNext.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Operators/OnErrorResumeNext.cs @@ -63,7 +63,7 @@ private static IEnumerable OnErrorResumeNextCore(IEnumerable Publish(this IEnumerable : IBuffer { private readonly object _gate = new object(); + private readonly RefCountList _buffer; + private readonly IEnumerator _source; - private RefCountList _buffer; private bool _disposed; private Exception? _error; - private IEnumerator _source; private bool _stopped; public PublishedBuffer(IEnumerator source) @@ -109,10 +109,7 @@ public void Dispose() if (!_disposed) { _source.Dispose(); - _source = null; - _buffer.Clear(); - _buffer = null; } _disposed = true; @@ -131,7 +128,7 @@ private IEnumerator GetEnumeratorCore(int i) } var hasValue = default(bool); - var current = default(T); + var current = default(T)!; lock (_gate) { diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Scan.cs b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Scan.cs index e0b77a6e7a..6c7854298b 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Scan.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Scan.cs @@ -65,7 +65,7 @@ private static IEnumerable ScanCore(IEnumerab private static IEnumerable ScanCore(IEnumerable source, Func accumulator) { var hasSeed = false; - var acc = default(TSource); + var acc = default(TSource)!; foreach (var item in source) { diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Share.cs b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Share.cs index 1418bd9704..65ee4d80da 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Operators/Share.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Operators/Share.cs @@ -58,8 +58,8 @@ public static IEnumerable Share(this IEnumerable : IBuffer { + private readonly IEnumerator _source; private bool _disposed; - private IEnumerator _source; public SharedBuffer(IEnumerator source) { @@ -89,7 +89,6 @@ public void Dispose() if (!_disposed) { _source.Dispose(); - _source = null; } _disposed = true; @@ -104,11 +103,15 @@ private sealed class ShareEnumerator : IEnumerator private bool _disposed; - public ShareEnumerator(SharedBuffer parent) => _parent = parent; + public ShareEnumerator(SharedBuffer parent) + { + _parent = parent; + Current = default!; + } public T Current { get; private set; } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; public void Dispose() => _disposed = true; @@ -138,7 +141,7 @@ public bool MoveNext() return true; } _disposed = true; - Current = default; + Current = default!; return false; } diff --git a/Ix.NET/Source/System.Interactive/System/Linq/RefCountList.cs b/Ix.NET/Source/System.Interactive/System/Linq/RefCountList.cs index 371a1a5203..6c46c7f66c 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/RefCountList.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/RefCountList.cs @@ -45,7 +45,7 @@ public T this[int i] public void Add(T item) { - _list[Count] = new RefCount { Value = item, Count = ReaderCount }; + _list[Count] = new RefCount(item, ReaderCount); Count++; } @@ -62,8 +62,14 @@ public void Done(int index) private sealed class RefCount { - public int Count; - public T Value; + public RefCount(T value, int count) + { + Value = value; + Count = count; + } + + public int Count { get; set; } + public T Value { get; } } } } diff --git a/Ix.NET/Source/System.Interactive/System/Linq/Yielder.cs b/Ix.NET/Source/System.Interactive/System/Linq/Yielder.cs index 9ee8f225b7..de19c0eb10 100644 --- a/Ix.NET/Source/System.Interactive/System/Linq/Yielder.cs +++ b/Ix.NET/Source/System.Interactive/System/Linq/Yielder.cs @@ -14,7 +14,11 @@ internal sealed class Yielder : IYielder, IAwaitable, IAwaiter private bool _running; private bool _stopped; - public Yielder(Action> create) => _create = create; + public Yielder(Action> create) + { + _create = create; + Current = default!; + } public T Current { get; private set; } diff --git a/Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableRewriter.cs b/Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableRewriter.cs index 17bbeb8f4b..aaabc42904 100644 --- a/Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableRewriter.cs +++ b/Ix.NET/Source/System.Linq.Async.Queryable/System/Linq/AsyncEnumerableRewriter.cs @@ -58,13 +58,14 @@ protected override Expression VisitMethodCall(MethodCallExpression node) return node; } + var declType = node.Method.DeclaringType; var typeArgs = node.Method.IsGenericMethod ? node.Method.GetGenericArguments() : null; // // Check whether the method is compatible with the recursively rewritten instance // and arguments expressions. If so, create a new call expression. // - if ((node.Method.IsStatic || node.Method.DeclaringType.IsAssignableFrom(obj.Type)) && ArgsMatch(node.Method, args, typeArgs)) + if ((node.Method.IsStatic || declType != null && declType.IsAssignableFrom(obj.Type)) && ArgsMatch(node.Method, args, typeArgs)) { return Expression.Call(obj, node.Method, args); } @@ -75,7 +76,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) // Find a corresponding method in the non-expression world, e.g. rewriting from // the AsyncQueryable methods to the ones on AsyncEnumerable. // - if (node.Method.DeclaringType == typeof(AsyncQueryable)) + if (declType == typeof(AsyncQueryable)) { method = FindEnumerableMethod(node.Method.Name, args, typeArgs); args = FixupQuotedArgs(method, args); @@ -83,7 +84,12 @@ protected override Expression VisitMethodCall(MethodCallExpression node) } else { - method = FindMethod(node.Method.DeclaringType, node.Method.Name, args, typeArgs, BindingFlags.Static | (node.Method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic)); + if (declType == null) + { + throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Could not rewrite method with name '{0}' without a DeclaringType.", node.Method.Name)); + } + + method = FindMethod(declType, node.Method.Name, args, typeArgs, BindingFlags.Static | (node.Method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic)); args = FixupQuotedArgs(method, args); } diff --git a/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/AsyncEnumerableNamingTests.cs b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/AsyncEnumerableNamingTests.cs index 6f6baf15de..d78bd71a38 100644 --- a/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/AsyncEnumerableNamingTests.cs +++ b/Ix.NET/Source/System.Linq.Async.Tests/System/Linq/AsyncEnumerableNamingTests.cs @@ -68,9 +68,9 @@ select GetDelegateKind(p.ParameterType)) static bool IsTaskLike(Type t) => IsTask(t) || IsValueTask(t); static bool IsDelegate(Type t) => typeof(Delegate).IsAssignableFrom(t); - static bool TryGetInvoke(Type t, out MethodInfo m) => (m = t.GetMethod("Invoke")) != null; - static bool IsAsyncDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && IsTaskLike(i.ReturnType); - static bool IsCancelableDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && i.GetParameters().LastOrDefault()?.ParameterType == typeof(CancellationToken); + static bool TryGetInvoke(Type t, out MethodInfo? m) => (m = t.GetMethod("Invoke")) != null; + static bool IsAsyncDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && IsTaskLike(i!.ReturnType); + static bool IsCancelableDelegate(Type t) => IsDelegate(t) && TryGetInvoke(t, out var i) && i!.GetParameters().LastOrDefault()?.ParameterType == typeof(CancellationToken); static DelegateKind GetDelegateKind(Type t) => IsAsyncDelegate(t) ? (IsCancelableDelegate(t) ? DelegateKind.AsyncCancel : DelegateKind.Async) : DelegateKind.Sync; } diff --git a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SingleLinkedNode.cs b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SingleLinkedNode.cs index e239f60363..441d70d46f 100644 --- a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SingleLinkedNode.cs +++ b/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SingleLinkedNode.cs @@ -86,14 +86,14 @@ public SingleLinkedNode GetNode(int index) { Debug.Assert(index >= 0 && index < GetCount()); - SingleLinkedNode? node = this; + SingleLinkedNode node = this; for (; index > 0; index--) { - node = node!.Linked; + node = node.Linked!; + Debug.Assert(node != null); } - Debug.Assert(node != null); - return node; + return node!; } ///