From 9b81faaf8f6f7b0837dba808bdc079eca8b46555 Mon Sep 17 00:00:00 2001
From: Marton Balassa <7115274+BalassaMarton@users.noreply.github.com>
Date: Fri, 14 Oct 2022 22:38:53 +0200
Subject: [PATCH] Experimental migration to netstandard2.1 using `ValueTask`
---
Nito.AsyncEx.sln | 4 +-
src/Directory.Build.props | 115 ++++++++----------
.../Nito.AsyncEx.Context.csproj | 17 ++-
src/Nito.AsyncEx.Coordination/AsyncLock.cs | 18 +--
src/Nito.AsyncEx.Coordination/AsyncMonitor.cs | 4 +-
.../AsyncReaderWriterLock.cs | 12 +-
.../AsyncSemaphore.cs | 6 +-
.../Nito.AsyncEx.Coordination.csproj | 23 ++--
.../Nito.AsyncEx.Interop.WaitHandles.csproj | 23 ++--
src/Nito.AsyncEx.Oop/Nito.AsyncEx.Oop.csproj | 15 ++-
src/Nito.AsyncEx.Tasks/AwaitableDisposable.cs | 67 ----------
.../Nito.AsyncEx.Tasks.csproj | 17 ++-
.../SemaphoreSlimExtensions.cs | 6 +-
src/Nito.AsyncEx/Nito.AsyncEx.csproj | 35 +++---
src/project.props | 2 +-
.../AsyncEx.Context.UnitTests.csproj | 19 ++-
.../AsyncEx.Coordination.UnitTests.csproj | 19 ++-
.../AsyncLockUnitTests.cs | 2 +-
.../AsyncReaderWriterLockUnitTests.cs | 2 +-
...yncEx.Interop.WaitHandles.UnitTests.csproj | 19 ++-
.../AsyncEx.Oop.UnitTests.csproj | 19 ++-
.../AsyncEx.Tasks.UnitTests.csproj | 19 ++-
test/Directory.Build.props | 7 +-
23 files changed, 180 insertions(+), 290 deletions(-)
delete mode 100644 src/Nito.AsyncEx.Tasks/AwaitableDisposable.cs
diff --git a/Nito.AsyncEx.sln b/Nito.AsyncEx.sln
index f35c932..1a90a6e 100644
--- a/Nito.AsyncEx.sln
+++ b/Nito.AsyncEx.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30517.126
+# Visual Studio Version 17
+VisualStudioVersion = 17.3.32922.545
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}"
EndProject
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 1b7687a..62a524f 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,5 +1,5 @@
-
-
+
+
+
+
+ netstandard2.1
+ true
+ latest
+ enable
+ true
+
+
+ true
+
+
+
+
+ https://github.com/$(GITHUB_REPOSITORY)
+ MIT
+
+
+
+
+ icon.png
+
+
+
+
+
+
+
+ true
+ true
+ true
+ snupkg
+
+
+
+
+
+
+
+ dev
+
+
+
+
+
+
-
-
- true
- latest
- enable
- true
-
-
- true
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
- https://github.com/$(GITHUB_REPOSITORY)
- MIT
-
-
-
-
- icon.png
-
-
-
-
-
-
-
- true
- true
- true
- snupkg
-
-
-
-
-
-
-
-
-
-
-
-
- dev
-
-
-
-
-
-
-
-
- <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/>
-
-
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Context/Nito.AsyncEx.Context.csproj b/src/Nito.AsyncEx.Context/Nito.AsyncEx.Context.csproj
index 614b429..2f1a03b 100644
--- a/src/Nito.AsyncEx.Context/Nito.AsyncEx.Context.csproj
+++ b/src/Nito.AsyncEx.Context/Nito.AsyncEx.Context.csproj
@@ -1,13 +1,12 @@
-
- A single-threaded async-compatible context.
- netstandard1.3;netstandard2.0;net461
- $(PackageTags);synchronizationcontext
-
+
+ A single-threaded async-compatible context.
+ $(PackageTags);synchronizationcontext
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Coordination/AsyncLock.cs b/src/Nito.AsyncEx.Coordination/AsyncLock.cs
index cfd4a57..90d9ea8 100644
--- a/src/Nito.AsyncEx.Coordination/AsyncLock.cs
+++ b/src/Nito.AsyncEx.Coordination/AsyncLock.cs
@@ -97,7 +97,7 @@ public int Id
///
/// The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).
/// A disposable that releases the lock when disposed.
- private Task RequestLockAsync(CancellationToken cancellationToken)
+ private ValueTask RequestLockAsync(CancellationToken cancellationToken)
{
lock (_mutex)
{
@@ -105,12 +105,14 @@ private Task RequestLockAsync(CancellationToken cancellationToken)
{
// If the lock is available, take it immediately.
_taken = true;
- return Task.FromResult(new Key(this));
+#pragma warning disable CA2000
+ return new ValueTask(new Key(this));
+#pragma warning restore CA2000
}
else
{
// Wait for the lock to become available or cancellation.
- return _queue.Enqueue(_mutex, cancellationToken);
+ return new ValueTask(_queue.Enqueue(_mutex, cancellationToken));
}
}
}
@@ -120,16 +122,16 @@ private Task RequestLockAsync(CancellationToken cancellationToken)
///
/// The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable LockAsync(CancellationToken cancellationToken)
+ public ValueTask LockAsync(CancellationToken cancellationToken)
{
- return new AwaitableDisposable(RequestLockAsync(cancellationToken));
+ return RequestLockAsync(cancellationToken);
}
///
/// Asynchronously acquires the lock. Returns a disposable that releases the lock when disposed.
///
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable LockAsync()
+ public ValueTask LockAsync()
{
return LockAsync(CancellationToken.None);
}
@@ -140,7 +142,9 @@ public AwaitableDisposable LockAsync()
/// The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).
public IDisposable Lock(CancellationToken cancellationToken)
{
- return RequestLockAsync(cancellationToken).WaitAndUnwrapException();
+ var task = RequestLockAsync(cancellationToken);
+
+ return task.IsCompleted ? task.Result : task.AsTask().Result;
}
///
diff --git a/src/Nito.AsyncEx.Coordination/AsyncMonitor.cs b/src/Nito.AsyncEx.Coordination/AsyncMonitor.cs
index e5e7802..afa4566 100644
--- a/src/Nito.AsyncEx.Coordination/AsyncMonitor.cs
+++ b/src/Nito.AsyncEx.Coordination/AsyncMonitor.cs
@@ -53,7 +53,7 @@ public int Id
///
/// The cancellation token used to cancel the enter. If this is already set, then this method will attempt to enter the monitor immediately (succeeding if the monitor is currently available).
/// A disposable that leaves the monitor when disposed.
- public AwaitableDisposable EnterAsync(CancellationToken cancellationToken)
+ public ValueTask EnterAsync(CancellationToken cancellationToken)
{
return _asyncLock.LockAsync(cancellationToken);
}
@@ -62,7 +62,7 @@ public AwaitableDisposable EnterAsync(CancellationToken cancellatio
/// Asynchronously enters the monitor. Returns a disposable that leaves the monitor when disposed.
///
/// A disposable that leaves the monitor when disposed.
- public AwaitableDisposable EnterAsync()
+ public ValueTask EnterAsync()
{
return EnterAsync(CancellationToken.None);
}
diff --git a/src/Nito.AsyncEx.Coordination/AsyncReaderWriterLock.cs b/src/Nito.AsyncEx.Coordination/AsyncReaderWriterLock.cs
index 0339cd7..f003986 100644
--- a/src/Nito.AsyncEx.Coordination/AsyncReaderWriterLock.cs
+++ b/src/Nito.AsyncEx.Coordination/AsyncReaderWriterLock.cs
@@ -131,16 +131,16 @@ private Task RequestReaderLockAsync(CancellationToken cancellationT
///
/// The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable ReaderLockAsync(CancellationToken cancellationToken)
+ public ValueTask ReaderLockAsync(CancellationToken cancellationToken)
{
- return new AwaitableDisposable(RequestReaderLockAsync(cancellationToken));
+ return new ValueTask(RequestReaderLockAsync(cancellationToken));
}
///
/// Asynchronously acquires the lock as a reader. Returns a disposable that releases the lock when disposed.
///
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable ReaderLockAsync()
+ public ValueTask ReaderLockAsync()
{
return ReaderLockAsync(CancellationToken.None);
}
@@ -198,16 +198,16 @@ private Task RequestWriterLockAsync(CancellationToken cancellationT
///
/// The cancellation token used to cancel the lock. If this is already set, then this method will attempt to take the lock immediately (succeeding if the lock is currently available).
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable WriterLockAsync(CancellationToken cancellationToken)
+ public ValueTask WriterLockAsync(CancellationToken cancellationToken)
{
- return new AwaitableDisposable(RequestWriterLockAsync(cancellationToken));
+ return new ValueTask(RequestWriterLockAsync(cancellationToken));
}
///
/// Asynchronously acquires the lock as a writer. Returns a disposable that releases the lock when disposed.
///
/// A disposable that releases the lock when disposed.
- public AwaitableDisposable WriterLockAsync()
+ public ValueTask WriterLockAsync()
{
return WriterLockAsync(CancellationToken.None);
}
diff --git a/src/Nito.AsyncEx.Coordination/AsyncSemaphore.cs b/src/Nito.AsyncEx.Coordination/AsyncSemaphore.cs
index 1250e09..991dc92 100644
--- a/src/Nito.AsyncEx.Coordination/AsyncSemaphore.cs
+++ b/src/Nito.AsyncEx.Coordination/AsyncSemaphore.cs
@@ -164,17 +164,17 @@ private async Task DoLockAsync(CancellationToken cancellationToken)
/// Asynchronously waits on the semaphore, and returns a disposable that releases the semaphore when disposed, thus treating this semaphore as a "multi-lock".
///
/// The cancellation token used to cancel the wait. If this is already set, then this method will attempt to take the slot immediately (succeeding if a slot is currently available).
- public AwaitableDisposable LockAsync(CancellationToken cancellationToken)
+ public ValueTask LockAsync(CancellationToken cancellationToken)
{
#pragma warning disable CA2000 // Dispose objects before losing scope
- return new AwaitableDisposable(DoLockAsync(cancellationToken));
+ return new ValueTask(DoLockAsync(cancellationToken));
#pragma warning restore CA2000 // Dispose objects before losing scope
}
///
/// Asynchronously waits on the semaphore, and returns a disposable that releases the semaphore when disposed, thus treating this semaphore as a "multi-lock".
///
- public AwaitableDisposable LockAsync() => LockAsync(CancellationToken.None);
+ public ValueTask LockAsync() => LockAsync(CancellationToken.None);
///
/// Synchronously waits on the semaphore, and returns a disposable that releases the semaphore when disposed, thus treating this semaphore as a "multi-lock".
diff --git a/src/Nito.AsyncEx.Coordination/Nito.AsyncEx.Coordination.csproj b/src/Nito.AsyncEx.Coordination/Nito.AsyncEx.Coordination.csproj
index 451c906..b71969a 100644
--- a/src/Nito.AsyncEx.Coordination/Nito.AsyncEx.Coordination.csproj
+++ b/src/Nito.AsyncEx.Coordination/Nito.AsyncEx.Coordination.csproj
@@ -1,17 +1,16 @@
-
- Asynchronous coordination primitives.
- netstandard1.3;netstandard2.0;net461
- $(PackageTags);asynclock;asynclazy
-
+
+ Asynchronous coordination primitives.
+ $(PackageTags);asynclock;asynclazy
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Interop.WaitHandles/Nito.AsyncEx.Interop.WaitHandles.csproj b/src/Nito.AsyncEx.Interop.WaitHandles/Nito.AsyncEx.Interop.WaitHandles.csproj
index 27e249e..1b14102 100644
--- a/src/Nito.AsyncEx.Interop.WaitHandles/Nito.AsyncEx.Interop.WaitHandles.csproj
+++ b/src/Nito.AsyncEx.Interop.WaitHandles/Nito.AsyncEx.Interop.WaitHandles.csproj
@@ -1,17 +1,16 @@
-
- Task wrappers for WaitHandles.
- netstandard1.3;netstandard2.0;net461
- $(PackageTags);waithandle
-
+
+ Task wrappers for WaitHandles.
+ $(PackageTags);waithandle
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Oop/Nito.AsyncEx.Oop.csproj b/src/Nito.AsyncEx.Oop/Nito.AsyncEx.Oop.csproj
index 08e8a2e..a7ceb12 100644
--- a/src/Nito.AsyncEx.Oop/Nito.AsyncEx.Oop.csproj
+++ b/src/Nito.AsyncEx.Oop/Nito.AsyncEx.Oop.csproj
@@ -1,12 +1,11 @@
-
- Interfaces and utility methods for combining async with OOP.
- netstandard1.3;netstandard2.0;net461
-
+
+ Interfaces and utility methods for combining async with OOP.
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Tasks/AwaitableDisposable.cs b/src/Nito.AsyncEx.Tasks/AwaitableDisposable.cs
deleted file mode 100644
index 5ee56bc..0000000
--- a/src/Nito.AsyncEx.Tasks/AwaitableDisposable.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using System.Runtime.CompilerServices;
-
-namespace Nito.AsyncEx
-{
- ///
- /// An awaitable wrapper around a task whose result is disposable. The wrapper is not disposable, so this prevents usage errors like "using (MyAsync())" when the appropriate usage should be "using (await MyAsync())".
- ///
- /// The type of the result of the underlying task.
-#pragma warning disable CA1815 // Override equals and operator equals on value types
- public readonly struct AwaitableDisposable where T : IDisposable
-#pragma warning restore CA1815 // Override equals and operator equals on value types
- {
- ///
- /// The underlying task.
- ///
- private readonly Task _task;
-
- ///
- /// Initializes a new awaitable wrapper around the specified task.
- ///
- /// The underlying task to wrap. This may not be null.
- public AwaitableDisposable(Task task)
- {
- if (task == null)
- throw new ArgumentNullException(nameof(task));
- _task = task;
- }
-
- ///
- /// Returns the underlying task.
- ///
- public Task AsTask()
- {
- return _task;
- }
-
- ///
- /// Implicit conversion to the underlying task.
- ///
- /// The awaitable wrapper.
-#pragma warning disable CA2225 // Operator overloads have named alternates
- public static implicit operator Task(AwaitableDisposable source)
-#pragma warning restore CA2225 // Operator overloads have named alternates
- {
- return source.AsTask();
- }
-
- ///
- /// Infrastructure. Returns the task awaiter for the underlying task.
- ///
- public TaskAwaiter GetAwaiter()
- {
- return _task.GetAwaiter();
- }
-
- ///
- /// Infrastructure. Returns a configured task awaiter for the underlying task.
- ///
- /// Whether to attempt to marshal the continuation back to the captured context.
- public ConfiguredTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
- {
- return _task.ConfigureAwait(continueOnCapturedContext);
- }
- }
-}
diff --git a/src/Nito.AsyncEx.Tasks/Nito.AsyncEx.Tasks.csproj b/src/Nito.AsyncEx.Tasks/Nito.AsyncEx.Tasks.csproj
index dbc86e3..28d7e51 100644
--- a/src/Nito.AsyncEx.Tasks/Nito.AsyncEx.Tasks.csproj
+++ b/src/Nito.AsyncEx.Tasks/Nito.AsyncEx.Tasks.csproj
@@ -1,13 +1,12 @@
-
- Common helper methods for tasks as used in asynchronous programming.
- netstandard1.3;netstandard2.0;net461
- $(PackageTags);taskfactory;cancellationtoken;taskcompletionsource
-
+
+ Common helper methods for tasks as used in asynchronous programming.
+ $(PackageTags);taskfactory;cancellationtoken;taskcompletionsource
+
-
-
-
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Nito.AsyncEx.Tasks/SemaphoreSlimExtensions.cs b/src/Nito.AsyncEx.Tasks/SemaphoreSlimExtensions.cs
index 6a5392a..13856e5 100644
--- a/src/Nito.AsyncEx.Tasks/SemaphoreSlimExtensions.cs
+++ b/src/Nito.AsyncEx.Tasks/SemaphoreSlimExtensions.cs
@@ -23,18 +23,18 @@ private static async Task DoLockAsync(SemaphoreSlim @this, Cancella
///
/// The semaphore to lock.
/// The cancellation token used to cancel the wait.
- public static AwaitableDisposable LockAsync(this SemaphoreSlim @this, CancellationToken cancellationToken)
+ public static ValueTask LockAsync(this SemaphoreSlim @this, CancellationToken cancellationToken)
{
_ = @this ?? throw new ArgumentNullException(nameof(@this));
#pragma warning disable CA2000 // Dispose objects before losing scope
- return new AwaitableDisposable(DoLockAsync(@this, cancellationToken));
+ return new ValueTask(DoLockAsync(@this, cancellationToken));
#pragma warning restore CA2000 // Dispose objects before losing scope
}
///
/// Asynchronously waits on the semaphore, and returns a disposable that releases the semaphore when disposed, thus treating this semaphore as a "multi-lock".
///
- public static AwaitableDisposable LockAsync(this SemaphoreSlim @this) => @this.LockAsync(CancellationToken.None);
+ public static ValueTask LockAsync(this SemaphoreSlim @this) => @this.LockAsync(CancellationToken.None);
///
/// Synchronously waits on the semaphore, and returns a disposable that releases the semaphore when disposed, thus treating this semaphore as a "multi-lock".
diff --git a/src/Nito.AsyncEx/Nito.AsyncEx.csproj b/src/Nito.AsyncEx/Nito.AsyncEx.csproj
index 99349fd..a1067d7 100644
--- a/src/Nito.AsyncEx/Nito.AsyncEx.csproj
+++ b/src/Nito.AsyncEx/Nito.AsyncEx.csproj
@@ -1,23 +1,22 @@
-
- Async and Task Helpers
- A helper library for the Task-Based Asynchronous Pattern (TAP).
- netstandard1.3;netstandard2.0;net461
- async;await;async-await;task;asynchronous;nito;nitro
- true
-
+
+ Async and Task Helpers
+ A helper library for the Task-Based Asynchronous Pattern (TAP).
+ async;await;async-await;task;asynchronous;nito;nitro
+ true
+
-
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/project.props b/src/project.props
index 11dba1f..f955cdf 100644
--- a/src/project.props
+++ b/src/project.props
@@ -1,6 +1,6 @@
- 5.1.2
+ 6.0.0
Stephen Cleary
task;async
Nito.AsyncEx
diff --git a/test/AsyncEx.Context.UnitTests/AsyncEx.Context.UnitTests.csproj b/test/AsyncEx.Context.UnitTests/AsyncEx.Context.UnitTests.csproj
index c937543..a38bac9 100644
--- a/test/AsyncEx.Context.UnitTests/AsyncEx.Context.UnitTests.csproj
+++ b/test/AsyncEx.Context.UnitTests/AsyncEx.Context.UnitTests.csproj
@@ -1,16 +1,11 @@
-
- netcoreapp3.1;net461
- netcoreapp3.1
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/AsyncEx.Coordination.UnitTests/AsyncEx.Coordination.UnitTests.csproj b/test/AsyncEx.Coordination.UnitTests/AsyncEx.Coordination.UnitTests.csproj
index 193d03a..35439c1 100644
--- a/test/AsyncEx.Coordination.UnitTests/AsyncEx.Coordination.UnitTests.csproj
+++ b/test/AsyncEx.Coordination.UnitTests/AsyncEx.Coordination.UnitTests.csproj
@@ -1,16 +1,11 @@
-
- netcoreapp3.1;net461
- netcoreapp3.1
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/AsyncEx.Coordination.UnitTests/AsyncLockUnitTests.cs b/test/AsyncEx.Coordination.UnitTests/AsyncLockUnitTests.cs
index 511dfde..4316ca6 100644
--- a/test/AsyncEx.Coordination.UnitTests/AsyncLockUnitTests.cs
+++ b/test/AsyncEx.Coordination.UnitTests/AsyncLockUnitTests.cs
@@ -199,7 +199,7 @@ public async Task AsyncLock_CanceledTooLate_StillTakesLock()
var mutex = new AsyncLock();
var cts = new CancellationTokenSource();
- AwaitableDisposable cancelableLockTask;
+ ValueTask cancelableLockTask;
using (await mutex.LockAsync())
{
cancelableLockTask = mutex.LockAsync(cts.Token);
diff --git a/test/AsyncEx.Coordination.UnitTests/AsyncReaderWriterLockUnitTests.cs b/test/AsyncEx.Coordination.UnitTests/AsyncReaderWriterLockUnitTests.cs
index caceaf8..d42afe0 100644
--- a/test/AsyncEx.Coordination.UnitTests/AsyncReaderWriterLockUnitTests.cs
+++ b/test/AsyncEx.Coordination.UnitTests/AsyncReaderWriterLockUnitTests.cs
@@ -227,7 +227,7 @@ public async Task ReadLock_WriteLockCanceled_TakesLock()
{
var writeKeyTask = rwl.WriterLockAsync(cts.Token);
writerLockReady.SetResult(null);
- await Assert.ThrowsAnyAsync(() => writeKeyTask);
+ await Assert.ThrowsAnyAsync(() => writeKeyTask.AsTask());
});
await writerLockReady.Task;
diff --git a/test/AsyncEx.Interop.WaitHandles.UnitTests/AsyncEx.Interop.WaitHandles.UnitTests.csproj b/test/AsyncEx.Interop.WaitHandles.UnitTests/AsyncEx.Interop.WaitHandles.UnitTests.csproj
index 7c27498..d30f0f0 100644
--- a/test/AsyncEx.Interop.WaitHandles.UnitTests/AsyncEx.Interop.WaitHandles.UnitTests.csproj
+++ b/test/AsyncEx.Interop.WaitHandles.UnitTests/AsyncEx.Interop.WaitHandles.UnitTests.csproj
@@ -1,16 +1,11 @@
-
- netcoreapp3.1;net461
- netcoreapp3.1
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/AsyncEx.Oop.UnitTests/AsyncEx.Oop.UnitTests.csproj b/test/AsyncEx.Oop.UnitTests/AsyncEx.Oop.UnitTests.csproj
index 6253a2b..6b435b7 100644
--- a/test/AsyncEx.Oop.UnitTests/AsyncEx.Oop.UnitTests.csproj
+++ b/test/AsyncEx.Oop.UnitTests/AsyncEx.Oop.UnitTests.csproj
@@ -1,16 +1,11 @@
-
- netcoreapp3.1;net461
- netcoreapp3.1
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/AsyncEx.Tasks.UnitTests/AsyncEx.Tasks.UnitTests.csproj b/test/AsyncEx.Tasks.UnitTests/AsyncEx.Tasks.UnitTests.csproj
index 8d91689..41753e1 100644
--- a/test/AsyncEx.Tasks.UnitTests/AsyncEx.Tasks.UnitTests.csproj
+++ b/test/AsyncEx.Tasks.UnitTests/AsyncEx.Tasks.UnitTests.csproj
@@ -1,16 +1,11 @@
-
- netcoreapp3.1;net461
- netcoreapp3.1
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
\ No newline at end of file
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
index 610d85e..7b06d6b 100644
--- a/test/Directory.Build.props
+++ b/test/Directory.Build.props
@@ -5,13 +5,14 @@
-->
- latest
+ net6.0
+ latest
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive