From 066b8683a514f60b709415847df3fcea920840fa Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Wed, 28 Oct 2015 14:23:54 +0900 Subject: [PATCH 01/10] Change assembly info to a non-varying version --- Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 1de0075..da878f6 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -34,4 +34,4 @@ // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("1.0.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] From 1fe5af1ad24458ec025e268415c259c469871cc9 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 7 Aug 2015 14:12:12 +0900 Subject: [PATCH 02/10] Added async / await classes --- StreamExtensions.cs | 464 ++++++++++++++++++ .../AsyncStateMachineAttribute.cs | 44 ++ .../AsyncTaskMethodBuilder.cs | 112 +++++ .../AsyncTaskMethodBuilder_T.cs | 112 +++++ .../AsyncVoidMethodBuilder.cs | 111 +++++ .../IAsyncStateMachine.cs | 40 ++ .../StateMachineAttribute.cs | 46 ++ System.Threading.Tasks.Net35.csproj | 7 + 8 files changed, 936 insertions(+) create mode 100644 StreamExtensions.cs create mode 100644 System.Runtime.CompilerServices/AsyncStateMachineAttribute.cs create mode 100644 System.Runtime.CompilerServices/AsyncTaskMethodBuilder.cs create mode 100644 System.Runtime.CompilerServices/AsyncTaskMethodBuilder_T.cs create mode 100644 System.Runtime.CompilerServices/AsyncVoidMethodBuilder.cs create mode 100644 System.Runtime.CompilerServices/IAsyncStateMachine.cs create mode 100644 System.Runtime.CompilerServices/StateMachineAttribute.cs diff --git a/StreamExtensions.cs b/StreamExtensions.cs new file mode 100644 index 0000000..3e96c30 --- /dev/null +++ b/StreamExtensions.cs @@ -0,0 +1,464 @@ +// +// StreamExtensions.cs +// +// Author: +// Jim Borden +// +// Copyright (c) 2015 Couchbase, Inc All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +using System; +using System.Threading.Tasks; +using System.Threading; + +namespace System.IO +{ + public static class StreamExtensions + { + + public static void CopyTo (this Stream source, Stream destination) + { + CopyTo (source, destination, 16*1024); + } + + public static void CopyTo (this Stream source, Stream destination, int bufferSize) + { + if (destination == null) + throw new ArgumentNullException ("destination"); + if (!source.CanRead) + throw new NotSupportedException ("This stream does not support reading"); + if (!destination.CanWrite) + throw new NotSupportedException ("This destination stream does not support writing"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException ("bufferSize"); + + var buffer = new byte [bufferSize]; + int nread; + while ((nread = source.Read (buffer, 0, bufferSize)) != 0) + destination.Write (buffer, 0, nread); + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream. + /// + /// + /// Copying begins at the current position in . + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync(this Stream stream, Stream destination) + { + #if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination); + #else + return CopyToAsync(stream, destination, 16 * 1024, CancellationToken.None); + #endif + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream, + /// using a specified buffer size. + /// + /// + /// Copying begins at the current position in . + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920. + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative or zero. + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync(this Stream stream, Stream destination, int bufferSize) + { + #if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination, bufferSize); + #else + return CopyToAsync(stream, destination, bufferSize, CancellationToken.None); + #endif + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream, + /// using a specified buffer size and cancellation token. + /// + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// Copying begins at the current position in . + /// + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920. + /// The token to monitor for cancellation requests. The default value is . + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative or zero. + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync(this Stream stream, Stream destination, int bufferSize, CancellationToken cancellationToken) + { + if (stream == null) + throw new ArgumentNullException("stream"); + if (destination == null) + throw new ArgumentNullException("destination"); + if (!stream.CanRead) + throw new NotSupportedException("The stream does not support reading"); + if (!destination.CanWrite) + throw new NotSupportedException("The destination does not support writing"); + if (bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + + if (cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + + #if NET45PLUS + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination, bufferSize, cancellationToken); + #else + return CopyToAsync(stream, destination, new byte[bufferSize], cancellationToken); + #endif + } + + #if !NET45PLUS + private static async Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) + { + int bytesRead; + while ((bytesRead = await ReadAsync(stream, buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) + { + await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); + } + } + #endif + + /// + /// Asynchronously clears all buffers for a stream and causes any buffered data to be written to the underlying device. + /// + /// + /// If a derived class does not flush the buffer in its implementation of the method, + /// the method will not flush the buffer. + /// + /// The stream to flush. + /// A task that represents the asynchronous flush operation. + /// If is . + /// If has been disposed. + public static Task FlushAsync(this Stream stream) + { + #if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.FlushAsync(); + #else + return FlushAsync(stream, CancellationToken.None); + #endif + } + + /// + /// Asynchronously clears all buffers for a stream and causes any buffered data to be written to the underlying device, + /// and monitors cancellation requests. + /// + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// If a derived class does not flush the buffer in its implementation of the method, + /// the method will not flush the buffer. + /// + /// + /// The stream to flush. + /// The token to monitor for cancellation requests. The default value is . + /// A task that represents the asynchronous flush operation. + /// If is . + /// If has been disposed. + public static Task FlushAsync(this Stream stream, CancellationToken cancellationToken) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + + #if NET45PLUS + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.FlushAsync(cancellationToken); + #else + return Task.Factory.StartNew(state => ((Stream)state).Flush(), stream, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + #endif + } + + /// + /// Asynchronously reads a sequence of bytes from a stream and advances the position within the stream by the number of bytes read. + /// + /// + /// Use the property to determine whether the stream instance supports reading. + /// + /// The stream to read data from. + /// The buffer to write the data into. + /// The byte offset in at which to begin writing data from the stream. + /// The maximum number of bytes to read. + /// + /// A task that represents the asynchronous read operation. When the task completes successfully, the + /// property contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if + /// the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support reading. + /// If has been disposed. + /// If is currently in use by a previous read operation. + public static Task ReadAsync(this Stream stream, byte[] buffer, int offset, int count) + { + #if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.ReadAsync(buffer, offset, count); + #else + return ReadAsync(stream, buffer, offset, count, CancellationToken.None); + #endif + } + + /// + /// Asynchronously reads a sequence of bytes from a stream, advances the position within the stream by the number of bytes read, + /// and monitors cancellation requests. + /// + /// + /// Use the property to determine whether the stream instance supports reading. + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// + /// The stream to read data from. + /// The buffer to write the data into. + /// The byte offset in at which to begin writing data from the stream. + /// The maximum number of bytes to read. + /// The token to monitor for cancellation requests. The default value is . + /// + /// A task that represents the asynchronous read operation. When the task completes successfully, the + /// property contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if + /// the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support reading. + /// If has been disposed. + /// If is currently in use by a previous read operation. + public static Task ReadAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + + #if NET45PLUS + // This code requires the `Stream` class provide an implementation of `ReadAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.ReadAsync(buffer, offset, count, cancellationToken); + #else + return Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, TaskCreationOptions.None); + #endif + } + + /// + /// Asynchronously writes a sequence of bytes to a stream and advances the position within the stream by the number of bytes written. + /// + /// + /// Use the property to determine whether the stream instance supports writing. + /// + /// The stream to write data to. + /// The buffer to read the data from. + /// The zero-based byte offset in buffer from which to begin copying bytes to the stream. + /// The maximum number of bytes to write. + /// + /// A task that represents the asynchronous write operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support writing. + /// If has been disposed. + /// If is currently in use by a previous write operation. + public static Task WriteAsync(this Stream stream, byte[] buffer, int offset, int count) + { + #if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.WriteAsync(buffer, offset, count); + #else + return WriteAsync(stream, buffer, offset, count, CancellationToken.None); + #endif + } + + /// + /// Asynchronously writes a sequence of bytes to a stream, advances the position within the stream by the number of bytes written, + /// and monitors cancellation requests. + /// + /// + /// Use the property to determine whether the stream instance supports writing. + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// + /// The stream to write data to. + /// The buffer to read the data from. + /// The zero-based byte offset in buffer from which to begin copying bytes to the stream. + /// The maximum number of bytes to write. + /// The token to monitor for cancellation requests. The default value is . + /// + /// A task that represents the asynchronous write operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support writing. + /// If has been disposed. + /// If is currently in use by a previous write operation. + public static Task WriteAsync(this Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (stream == null) + throw new ArgumentNullException("stream"); + + if (cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + + #if NET45PLUS + // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.WriteAsync(buffer, offset, count, cancellationToken); + #else + return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, count, null); + #endif + } + + private static Task GetCanceledTask() + { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } + } +} + diff --git a/System.Runtime.CompilerServices/AsyncStateMachineAttribute.cs b/System.Runtime.CompilerServices/AsyncStateMachineAttribute.cs new file mode 100644 index 0000000..2eb7d92 --- /dev/null +++ b/System.Runtime.CompilerServices/AsyncStateMachineAttribute.cs @@ -0,0 +1,44 @@ +// +// AsyncStateMachineAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2012 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Method, Inherited = false)] + [Serializable] + public sealed class AsyncStateMachineAttribute : StateMachineAttribute + { + public AsyncStateMachineAttribute (Type stateMachineType) + : base (stateMachineType) + { + } + } +} + +#endif \ No newline at end of file diff --git a/System.Runtime.CompilerServices/AsyncTaskMethodBuilder.cs b/System.Runtime.CompilerServices/AsyncTaskMethodBuilder.cs new file mode 100644 index 0000000..e032494 --- /dev/null +++ b/System.Runtime.CompilerServices/AsyncTaskMethodBuilder.cs @@ -0,0 +1,112 @@ +// +// AsyncTaskMethodBuilder.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2011 Novell, Inc (http://www.novell.com) +// Copyright (C) 2011 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +using System.Threading; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + public struct AsyncTaskMethodBuilder + { + readonly Task task; + IAsyncStateMachine stateMachine; + + private AsyncTaskMethodBuilder (Task task) + { + this.task = task; + this.stateMachine = null; + } + + public Task Task { + get { + return task; + } + } + + public void AwaitOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.OnCompleted (action); + } + + public void AwaitUnsafeOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.UnsafeOnCompleted (action); + } + + public static AsyncTaskMethodBuilder Create () + { + var task = new Task (TaskActionInvoker.Promise, null, CancellationToken.None, TaskCreationOptions.None, null); + task.SetupScheduler (TaskScheduler.Current); + return new AsyncTaskMethodBuilder (task); + } + + public void SetException (Exception exception) + { + if (Task.TrySetException (new AggregateException (exception), exception is OperationCanceledException, true)) + return; + + throw new InvalidOperationException ("The task has already completed"); + } + + public void SetStateMachine (IAsyncStateMachine stateMachine) + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + if (this.stateMachine != null) + throw new InvalidOperationException ("The state machine was previously set"); + + this.stateMachine = stateMachine; + } + + public void SetResult () + { + if (!task.TrySetResult (null)) + throw new InvalidOperationException ("The task has already completed"); + } + + public void Start (ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + stateMachine.MoveNext (); + } + } +} + +#endif \ No newline at end of file diff --git a/System.Runtime.CompilerServices/AsyncTaskMethodBuilder_T.cs b/System.Runtime.CompilerServices/AsyncTaskMethodBuilder_T.cs new file mode 100644 index 0000000..3140556 --- /dev/null +++ b/System.Runtime.CompilerServices/AsyncTaskMethodBuilder_T.cs @@ -0,0 +1,112 @@ +// +// AsyncTaskMethodBuilder_T.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2011 Novell, Inc (http://www.novell.com) +// Copyright (C) 2011 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +using System.Threading; +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + public struct AsyncTaskMethodBuilder + { + readonly Task task; + IAsyncStateMachine stateMachine; + + private AsyncTaskMethodBuilder (Task task) + { + this.task = task; + this.stateMachine = null; + } + + public Task Task { + get { + return task; + } + } + + public void AwaitOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.OnCompleted (action); + } + + public void AwaitUnsafeOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.UnsafeOnCompleted (action); + } + + public static AsyncTaskMethodBuilder Create () + { + var task = new Task (TaskActionInvoker.Promise, null, CancellationToken.None, TaskCreationOptions.None, null); + task.SetupScheduler (TaskScheduler.Current); + return new AsyncTaskMethodBuilder (task); + } + + public void SetException (Exception exception) + { + if (Task.TrySetException (new AggregateException (exception), exception is OperationCanceledException, true)) + return; + + throw new InvalidOperationException ("The task has already completed"); + } + + public void SetStateMachine (IAsyncStateMachine stateMachine) + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + if (this.stateMachine != null) + throw new InvalidOperationException ("The state machine was previously set"); + + this.stateMachine = stateMachine; + } + + public void SetResult (TResult result) + { + if (!task.TrySetResult (result)) + throw new InvalidOperationException ("The task has already completed"); + } + + public void Start (ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + stateMachine.MoveNext (); + } + } +} + +#endif \ No newline at end of file diff --git a/System.Runtime.CompilerServices/AsyncVoidMethodBuilder.cs b/System.Runtime.CompilerServices/AsyncVoidMethodBuilder.cs new file mode 100644 index 0000000..7f7b7e4 --- /dev/null +++ b/System.Runtime.CompilerServices/AsyncVoidMethodBuilder.cs @@ -0,0 +1,111 @@ +// +// AsyncVoidMethodBuilder.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2011 Novell, Inc (http://www.novell.com) +// Copyright (C) 2011 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +using System.Threading; + +namespace System.Runtime.CompilerServices +{ + public struct AsyncVoidMethodBuilder + { + static readonly SynchronizationContext null_context = new SynchronizationContext (); + + readonly SynchronizationContext context; + IAsyncStateMachine stateMachine; + + private AsyncVoidMethodBuilder (SynchronizationContext context) + { + this.context = context; + this.stateMachine = null; + } + + public void AwaitOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : INotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.OnCompleted (action); + } + + public void AwaitUnsafeOnCompleted (ref TAwaiter awaiter, ref TStateMachine stateMachine) + where TAwaiter : ICriticalNotifyCompletion + where TStateMachine : IAsyncStateMachine + { + var action = new Action (stateMachine.MoveNext); + awaiter.UnsafeOnCompleted (action); + } + + public static AsyncVoidMethodBuilder Create () + { + var ctx = SynchronizationContext.Current ?? null_context; + ctx.OperationStarted (); + + return new AsyncVoidMethodBuilder (ctx); + } + + public void SetException (Exception exception) + { + if (exception == null) + throw new ArgumentNullException ("exception"); + + try { + context.Post (l => { throw (Exception) l; }, exception); + } finally { + SetResult (); + } + } + + public void SetStateMachine (IAsyncStateMachine stateMachine) + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + if (this.stateMachine != null) + throw new InvalidOperationException ("The state machine was previously set"); + + this.stateMachine = stateMachine; + } + + public void SetResult () + { + context.OperationCompleted (); + } + + public void Start (ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + if (stateMachine == null) + throw new ArgumentNullException ("stateMachine"); + + stateMachine.MoveNext (); + } + } +} + +#endif \ No newline at end of file diff --git a/System.Runtime.CompilerServices/IAsyncStateMachine.cs b/System.Runtime.CompilerServices/IAsyncStateMachine.cs new file mode 100644 index 0000000..86774b7 --- /dev/null +++ b/System.Runtime.CompilerServices/IAsyncStateMachine.cs @@ -0,0 +1,40 @@ +// +// IAsyncStateMachine.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2012 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +namespace System.Runtime.CompilerServices +{ + public interface IAsyncStateMachine + { + void MoveNext (); + void SetStateMachine (IAsyncStateMachine stateMachine); + } +} + +#endif \ No newline at end of file diff --git a/System.Runtime.CompilerServices/StateMachineAttribute.cs b/System.Runtime.CompilerServices/StateMachineAttribute.cs new file mode 100644 index 0000000..872241e --- /dev/null +++ b/System.Runtime.CompilerServices/StateMachineAttribute.cs @@ -0,0 +1,46 @@ +// +// StateMachineAttribute.cs +// +// Authors: +// Marek Safar +// +// Copyright (C) 2012 Xamarin, Inc (http://www.xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +#if NET_4_5 + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage (AttributeTargets.Method, Inherited = false)] + [Serializable] + public class StateMachineAttribute : Attribute + { + public StateMachineAttribute (Type stateMachineType) + { + StateMachineType = stateMachineType; + } + + public Type StateMachineType { get; private set; } + } +} + +#endif \ No newline at end of file diff --git a/System.Threading.Tasks.Net35.csproj b/System.Threading.Tasks.Net35.csproj index f758e87..f00faaf 100644 --- a/System.Threading.Tasks.Net35.csproj +++ b/System.Threading.Tasks.Net35.csproj @@ -102,6 +102,13 @@ + + + + + + + From 35c006ba3f4961fc7ac6362966b84ce3d2fc5695 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Tue, 10 Nov 2015 16:53:58 -0800 Subject: [PATCH 03/10] Separate into regular .NET 3.5 and Unity since they are so different... --- StreamExtensions.cs | 18 +++++ System.Threading.Tasks.Net35.csproj | 2 +- System.Threading.Tasks.Unity.csproj | 120 ++++++++++++++++++++++++++++ UnityExt.cs | 47 +++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 System.Threading.Tasks.Unity.csproj create mode 100644 UnityExt.cs diff --git a/StreamExtensions.cs b/StreamExtensions.cs index 3e96c30..f2a8bc2 100644 --- a/StreamExtensions.cs +++ b/StreamExtensions.cs @@ -189,7 +189,23 @@ public static Task CopyToAsync(this Stream stream, Stream destination, int buffe #endif } + + #if !NET45PLUS + #if UNITY + private static Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) + { + int bytesRead; + while ((bytesRead = ReadAsync(stream, buffer, 0, buffer.Length, cancellationToken).Await()) != 0) + { + destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).Await(); + } + + return Task.FromResult(true); + } + + #else + private static async Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) { int bytesRead; @@ -198,6 +214,8 @@ private static async Task CopyToAsync(Stream stream, Stream destination, byte[] await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); } } + + #endif #endif /// diff --git a/System.Threading.Tasks.Net35.csproj b/System.Threading.Tasks.Net35.csproj index f00faaf..e412b16 100644 --- a/System.Threading.Tasks.Net35.csproj +++ b/System.Threading.Tasks.Net35.csproj @@ -8,7 +8,7 @@ System.Threading.Tasks.Net35 System.Threading.Tasks.Net35 v3.5 - 1.1.1 + 1.1 False diff --git a/System.Threading.Tasks.Unity.csproj b/System.Threading.Tasks.Unity.csproj new file mode 100644 index 0000000..b5df6e0 --- /dev/null +++ b/System.Threading.Tasks.Unity.csproj @@ -0,0 +1,120 @@ + + + + Debug + AnyCPU + {DCB5D745-525C-46A1-BFC0-E12F87AB6165} + Library + System.Threading.Tasks.Net35 + System.Threading.Tasks.Net35 + v3.5 + 1.1 + False + + + True + full + False + bin\Debug + DEBUG;TRACE;NET_4_5;UNITY + prompt + 4 + False + True + + + True + bin\Release + prompt + 4 + False + True + NET_4_5;UNITY + pdbonly + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UnityExt.cs b/UnityExt.cs new file mode 100644 index 0000000..3fbe8f7 --- /dev/null +++ b/UnityExt.cs @@ -0,0 +1,47 @@ +// +// UnityExt.cs +// +// Author: +// Jim Borden +// +// Copyright (c) 2015 Couchbase, Inc All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//#if UNITY +using System.Threading.Tasks; +using System.Threading; + +namespace System +{ + internal static class UnityExt + { + public static T Await(this Task t) + { + using(var mre = new ManualResetEventSlim()) { + t.ConfigureAwait(false).GetAwaiter().OnCompleted(mre.Set); + mre.Wait(); + return t.Result; + } + } + + public static void Await(this Task t) + { + using(var mre = new ManualResetEventSlim()) { + t.ConfigureAwait(false).GetAwaiter().OnCompleted(mre.Set); + mre.Wait(); + } + } + } +} +//#endif \ No newline at end of file From 7bbc51c2cd164552f0e52e12d4730d67d7d5aa16 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Sat, 14 Nov 2015 11:09:41 -0800 Subject: [PATCH 04/10] Added some more needed extensions --- StreamExtensions.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/StreamExtensions.cs b/StreamExtensions.cs index f2a8bc2..9f5bb25 100644 --- a/StreamExtensions.cs +++ b/StreamExtensions.cs @@ -21,12 +21,22 @@ using System; using System.Threading.Tasks; using System.Threading; +using System.Net; namespace System.IO { public static class StreamExtensions { - + public static Task GetRequestStreamAsync(this WebRequest request) + { + return Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null); + } + + public static Task GetResponseAsync(this WebRequest request) + { + return Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null); + } + public static void CopyTo (this Stream source, Stream destination) { CopyTo (source, destination, 16*1024); From 7f3473625bca33586ae1b74cc75945ed582def47 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Tue, 1 Dec 2015 08:49:34 -0500 Subject: [PATCH 05/10] Spike test for issue 523 --- System.Runtime.CompilerServices/YieldAwaitable.cs | 8 ++++---- System.Threading.Tasks/TaskContinuation.cs | 2 +- System.Threading.Tasks/TpScheduler.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/System.Runtime.CompilerServices/YieldAwaitable.cs b/System.Runtime.CompilerServices/YieldAwaitable.cs index 3ba0446..e8fee53 100644 --- a/System.Runtime.CompilerServices/YieldAwaitable.cs +++ b/System.Runtime.CompilerServices/YieldAwaitable.cs @@ -71,11 +71,11 @@ void OnCompleted (Action continuation, bool isUnsafe) // hoisting class // WaitCallback callBack = l => ((Action) l) (); - if (isUnsafe) { - ThreadPool.UnsafeQueueUserWorkItem (callBack, continuation); - } else { + //if (isUnsafe) { + // ThreadPool.UnsafeQueueUserWorkItem (callBack, continuation); + //} else { ThreadPool.QueueUserWorkItem (callBack, continuation); - } + //} return; } diff --git a/System.Threading.Tasks/TaskContinuation.cs b/System.Threading.Tasks/TaskContinuation.cs index fb98302..7956431 100644 --- a/System.Threading.Tasks/TaskContinuation.cs +++ b/System.Threading.Tasks/TaskContinuation.cs @@ -126,7 +126,7 @@ public void Execute () if ((SynchronizationContext.Current == null || SynchronizationContext.Current.GetType () == typeof (SynchronizationContext)) && TaskScheduler.IsDefault) { action (); } else { - ThreadPool.UnsafeQueueUserWorkItem (l => ((Action) l) (), action); + ThreadPool.QueueUserWorkItem (l => ((Action) l) (), action); } } } diff --git a/System.Threading.Tasks/TpScheduler.cs b/System.Threading.Tasks/TpScheduler.cs index 5f29ce1..f4a9c08 100644 --- a/System.Threading.Tasks/TpScheduler.cs +++ b/System.Threading.Tasks/TpScheduler.cs @@ -48,7 +48,7 @@ protected internal override void QueueTask (Task task) return; } - ThreadPool.UnsafeQueueUserWorkItem (callback, task); + ThreadPool.QueueUserWorkItem (callback, task); } static void TaskExecuterCallback (object obj) From 3fb64f2209547e529046c31da07d3e16cc41dd5e Mon Sep 17 00:00:00 2001 From: andyhebear Date: Tue, 19 Oct 2021 09:56:22 +0800 Subject: [PATCH 06/10] support dotnet2.0 --- .vs/System.Threading.Tasks.Net20/v14/.suo | Bin 0 -> 10240 bytes NET20-35/Action20.cs | 54 ++++++++++ NET20-35/Action35.cs | 54 ++++++++++ System.Threading.Tasks.Net20.csproj | 114 ++++++++++++++++++++++ System.Threading.Tasks.Net20.csproj.user | 6 ++ System.Threading.Tasks.Net35.csproj | 8 +- System.Threading.Tasks.Net35.csproj.user | 6 ++ System.Threading.Tasks/TaskExtensions.cs | 20 +++- System/Funcs.cs | 8 +- 9 files changed, 262 insertions(+), 8 deletions(-) create mode 100644 .vs/System.Threading.Tasks.Net20/v14/.suo create mode 100644 NET20-35/Action20.cs create mode 100644 NET20-35/Action35.cs create mode 100644 System.Threading.Tasks.Net20.csproj create mode 100644 System.Threading.Tasks.Net20.csproj.user create mode 100644 System.Threading.Tasks.Net35.csproj.user diff --git a/.vs/System.Threading.Tasks.Net20/v14/.suo b/.vs/System.Threading.Tasks.Net20/v14/.suo new file mode 100644 index 0000000000000000000000000000000000000000..4dc30b83bec729342236ba498ac18d99b93d6636 GIT binary patch literal 10240 zcmeHNeN2^A7(aj?5m{n|NhBmn*ait?88wxXk4lO7Xw_~SAqvRHjW5Ma{72i=a{SSp zGT2xjv}kRvkI`65mu{qO+2&?#S&&xzVJn^f;U94O{oeN+c;5@}``&vY>W+Kv&U?O| zbDod$Jm);mfwSL54|E-i9TZ+^wTKWSo=7pr&>v=~i}^wuW8a9!p7k{*{K#1uZ-WjJ6+%KH4?yUcu4+)mdk>e>EN| zgG&O+e~ZAra__m<^!ca{+-K?l?+Bj%9H;Fn9Wn0z?dZP)`A#{$5anI69*gpBS-%J6 zVp&f>d9SP|qFgHLNht4=_2nq`}MG7KIlmT-k1XZi`q@vv*im&cY zZr{A`l4rH+@~+_@&yzl*nzF8u{pC-c*@s#l$jQ6b+V|ThJvRvGPkJlNKL*TOR_KHM zN$FY;Mg60HNS~2RS%8_k7opW5dz|$D5!1}^4c`C6%QMAS{BeLiESGY^ziK>6QxEae zC#Ik5EB<)E`pW;qCT!yyihtr}8V@nPX9>C#|Dp5W{{1fv#%`B_{rq>*|1=zRb}3~4 z!EOIdxVCtG)!=eY6@~cLXm`H4z&D_$0l!ksGvNEUOJt$lf_Y^cd;>1cYOJAOe2GUk zWY#2qbSC-w@vq*#5U&}Jelm@Hjrz1>GS`>A$Ke|FK5{@lZ)rNWEt1fq9iLyVdVERL z4Mmcv(`MjpnlE3l`mR5jWSiT z^^(t&`d{?Rbp8&-ZR(i&YkTBD@#yxR?&!ZQDH+BH-wxolZ@kZYje`*Wu|IFV1y)U~Pd!yVF+Q(KHlhgVCFQ4CTJVcZst}I7P$!msB6S{@J za5OuqJ1*<>!R~_ezC8o{JLKs3ZE@BR#5>goe*R4q@w&tlxMlQ9mBI6NoR8U}8FcfS z)hX{woHeJ({mZ(F{`GAy?Q1(pk`%?N^d{4?J;m}T{iWKOUJhwjqpo7xVsNuf<3s0S zBx3J-XMeubvFQ89zRf+;wlP31s-{-{#utaN`(LNHzpEv8|G8_+tIx%IdPd5Q7%5)X zCB*Z%>HU`fuIZrP?7wV+U!!w$;_%=%!?90C{qa}9jXgspCTFW0ugs_5!=&S{G6xZH zTX42}I_T%)BLAVH7M_CsQldPDjIR%DX?^!%f9IbcoX&Wv@3L`EEGRac!erl1%&X17 c79aAMr|bQX{zvHjkGib|)|1uW$-e*n13HwsRsaA1 literal 0 HcmV?d00001 diff --git a/NET20-35/Action20.cs b/NET20-35/Action20.cs new file mode 100644 index 0000000..7bd95ec --- /dev/null +++ b/NET20-35/Action20.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#if NET20 + +namespace System +{ + // public delegate void Action(T obj); + +//#if NET20 + public delegate void Action(); + public delegate void Action(T1 arg1, T2 arg2); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + public delegate TResult Func(); + public delegate TResult Func(T arg); + public delegate TResult Func(T1 arg1, T2 arg2); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); +//#endif + + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + // More + + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); + + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); +} + +#endif diff --git a/NET20-35/Action35.cs b/NET20-35/Action35.cs new file mode 100644 index 0000000..7a88547 --- /dev/null +++ b/NET20-35/Action35.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +//#if NET35 + +namespace System +{ + // public delegate void Action(T obj); + +#if NET20 + //public delegate void Action(); + //public delegate void Action(T1 arg1, T2 arg2); + //public delegate void Action(T1 arg1, T2 arg2, T3 arg3); + //public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4); + + //public delegate TResult Func(); + //public delegate TResult Func(T arg); + //public delegate TResult Func(T1 arg1, T2 arg2); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4); +#endif + + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + + // More + + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); + public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); + + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15); + public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16); +} + +//#endif diff --git a/System.Threading.Tasks.Net20.csproj b/System.Threading.Tasks.Net20.csproj new file mode 100644 index 0000000..ff1996d --- /dev/null +++ b/System.Threading.Tasks.Net20.csproj @@ -0,0 +1,114 @@ + + + + Debug + AnyCPU + {DCB5D745-525C-46A1-BFC0-E12F87AB6165} + Library + System.Threading.Tasks.Net20 + System.Threading.Tasks.Net20 + v2.0 + 1.1.1 + False + + + + True + full + False + bin\Debug + TRACE;DEBUG;NET_4_5;NET20 + prompt + 4 + False + True + x86 + + + True + bin\Release + prompt + 4 + False + True + NET_4_5;NET20 + pdbonly + true + x86 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/System.Threading.Tasks.Net20.csproj.user b/System.Threading.Tasks.Net20.csproj.user new file mode 100644 index 0000000..5283ef1 --- /dev/null +++ b/System.Threading.Tasks.Net20.csproj.user @@ -0,0 +1,6 @@ + + + + ShowAllFiles + + \ No newline at end of file diff --git a/System.Threading.Tasks.Net35.csproj b/System.Threading.Tasks.Net35.csproj index f758e87..f399e4e 100644 --- a/System.Threading.Tasks.Net35.csproj +++ b/System.Threading.Tasks.Net35.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - {DCB5D745-525C-46A1-BFC0-E12F87AB6165} + {F1D8592C-3CCD-4844-81AA-BBE0700A43E5} Library System.Threading.Tasks.Net35 System.Threading.Tasks.Net35 @@ -15,12 +15,13 @@ True full False - bin\Debug + bin\Debug\ DEBUG;TRACE;NET_4_5; prompt 4 False True + x86 True @@ -32,8 +33,10 @@ NET_4_5; pdbonly true + x86 + @@ -83,7 +86,6 @@ - diff --git a/System.Threading.Tasks.Net35.csproj.user b/System.Threading.Tasks.Net35.csproj.user new file mode 100644 index 0000000..ca1d04b --- /dev/null +++ b/System.Threading.Tasks.Net35.csproj.user @@ -0,0 +1,6 @@ + + + + ProjectFiles + + \ No newline at end of file diff --git a/System.Threading.Tasks/TaskExtensions.cs b/System.Threading.Tasks/TaskExtensions.cs index eac0c66..07d1fda 100644 --- a/System.Threading.Tasks/TaskExtensions.cs +++ b/System.Threading.Tasks/TaskExtensions.cs @@ -30,7 +30,24 @@ namespace System.Threading.Tasks { - public static class TaskExtensions +#if NET20 + public static class TaskExtensions { + public static Task Unwrap(Task> task) { + if(task == null) + throw new ArgumentNullException("task"); + + return TaskExtensionsImpl.Unwrap(task); + } + + public static Task Unwrap(Task task) { + if(task == null) + throw new ArgumentNullException("task"); + + return TaskExtensionsImpl.Unwrap(task); + } + } +#else + public static class TaskExtensions { public static Task Unwrap (this Task> task) { @@ -48,4 +65,5 @@ public static Task Unwrap (this Task task) return TaskExtensionsImpl.Unwrap (task); } } +#endif } diff --git a/System/Funcs.cs b/System/Funcs.cs index 6221765..63dd2e4 100644 --- a/System/Funcs.cs +++ b/System/Funcs.cs @@ -27,9 +27,9 @@ namespace System { - public delegate TResult Func (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); - public delegate TResult Func (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); - public delegate TResult Func (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); - public delegate TResult Func (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); + //public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); } From fa436eeff08fa204c136de64ee640a03af6991b6 Mon Sep 17 00:00:00 2001 From: RainsSoft Date: Tue, 19 Oct 2021 10:34:16 +0800 Subject: [PATCH 07/10] Create README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持.net2.0 --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4e13c9a --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# dotnet-tpl20 +A backport of the Task Parallel Library to .NET 2.0 + dotnet.20支持dotnet4.0的Task From e6c49b4711f792173ab39a28ed80855265cf3dce Mon Sep 17 00:00:00 2001 From: andyhebear Date: Tue, 19 Oct 2021 10:43:30 +0800 Subject: [PATCH 08/10] Update .suo --- .vs/System.Threading.Tasks.Net20/v14/.suo | Bin 10240 -> 9728 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.vs/System.Threading.Tasks.Net20/v14/.suo b/.vs/System.Threading.Tasks.Net20/v14/.suo index 4dc30b83bec729342236ba498ac18d99b93d6636..2060ab8edb45556c884764c9aeaedad8a0cbb967 100644 GIT binary patch delta 527 zcmZn&Xz-a}Aj`x61p*8VEI=kB5dZuC|365Sd2*tZ@WuolCcX*9mwrq-a-ES6DC)pH zxr(WZQD^g4CT>PXw#kev;*7kL9XZ4$`GKQ$M0b-2q=C5qRj0PM)k-tEtAgf^j#O4HwgN)<`Vjds{SpkyYY{Bt`Q2^u| zULXdk)CSU%ZMX_Jb)W+OHU@e#PU6zRs%o+bi^%2!d^;GKT$naji7jK?tibbtagsm< zQx}Ne#ym;py1G5Lyety~H1Sv_ba$pF7T*JsPxk1)~*@(daPVbg= zVzijNUP@>323elTjj}bo`@jkzp;|JzQ7Q^3!yyIK!=T5I%uviwz)-}H&yWQUb&Ftz z%1OcvlLci>xk91(JPao97j|4E#k5F-iDDPAFfmvJZ~iZTkY#d%kQZD1?x&kq|D4>& KYcTnM$^ihqv7dzi delta 559 zcmZqhX$Y8LAj<#)0t^gnKsF-~|NH;{KS-Eya-x**#snTFK7stLJ9>{?XXFEl9^jf> z#Z<+}xA`j*HzOn0WJVV8$y>Mt6uE(NtU$~U#6Sc73jt}Mp$vjR3^I`iV%h@6i3u!| z*m8MytOFa#3zS9}$tKKbzz!7o3)BG81i~P|2^8Z2Vvq$8k^lce7I6UaW($rli~=B) zAhTe)CfjfoZ1&&?VO%7@G>J zifNMAb%B1F__^$lW^?v1SeLI}F8E<`f|MlBU!W( mZ<4Buse)nifBAzfK$jetoS@ps334U~Bm2jU4`d68egXiSS*vsa From 9d90995d1be1f345b5b61133cc4f562a8c6dd299 Mon Sep 17 00:00:00 2001 From: andyhebear Date: Tue, 19 Oct 2021 11:31:19 +0800 Subject: [PATCH 09/10] =?UTF-8?q?.net2.0=E5=A2=9E=E5=8A=A0StreamExtensions?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1:.net2.0增加StreamExtensions支持 2:增加测试 --- .vs/System.Threading.Tasks.Net20/v14/.suo | Bin 9728 -> 139264 bytes Action20-35 | 1 - StreamExtensions.cs | 573 +++++++++++++++++- System.Threading.Tasks.Net20.csproj | 3 +- System.Threading.Tasks.Net20.sln | 40 ++ System.Threading.Tasks.Unity.csproj | 5 +- System.Threading.Tasks.Unity.csproj.user | 6 + System.Threading.Tasks/TaskExtensions.cs | 15 + .../Program.cs | 33 + .../Properties/AssemblyInfo.cs | 36 ++ .../System.Threading.Tasks.Net20.Test.csproj | 61 ++ .../app.config | 3 + 12 files changed, 740 insertions(+), 36 deletions(-) delete mode 100644 Action20-35 create mode 100644 System.Threading.Tasks.Net20.sln create mode 100644 System.Threading.Tasks.Unity.csproj.user create mode 100644 Test/System.Threading.Tasks.Net20.Test/Program.cs create mode 100644 Test/System.Threading.Tasks.Net20.Test/Properties/AssemblyInfo.cs create mode 100644 Test/System.Threading.Tasks.Net20.Test/System.Threading.Tasks.Net20.Test.csproj create mode 100644 Test/System.Threading.Tasks.Net20.Test/app.config diff --git a/.vs/System.Threading.Tasks.Net20/v14/.suo b/.vs/System.Threading.Tasks.Net20/v14/.suo index 2060ab8edb45556c884764c9aeaedad8a0cbb967..97e972b0670c77869589d03512dbddc08ce0ccca 100644 GIT binary patch literal 139264 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 EKhWzTz5oCK delta 889 zcmc&yO=uHQ5T1GY>843jyNei)t!-h?|0q)M=bJ%ou>`8fhK)dO-(X12F;x}X)U!# zePwyUK}?_6WL7N8_`x;zn`n$MA3kpxM@HEhV(1L+0}O@)7x)bQxsJ~b+%7sVzV1l} z!_2mm4k~}|fOdxtS4C-H;^#PB#PSRg5b?pih>tNuw2PC2Wu%1Sm<*pXjHJuRQi>+0 zo@C@QeA8c!AdS1?m~o{*GQiw=|!NcP-ky+9_HoIhynh&3t>^$lyd%%sNv z@WZDH3#+^d(d9#V_7^-$%TXHlxwiLc8&8ehg`2Pfr@?{>oPjFbklaf=pRAw zHYpu{KC)-;$A4;O3D&npu}z=4)%>+z5tl5W;G|8<7mI$e{tey#HB(x_%#t4+Lq+z4 nLDuDQ@5(LA`m@eE-1>ll_v$z*%tVcGKR>lpk5`o0Kf diff --git a/Action20-35 b/Action20-35 deleted file mode 100644 index 8b13789..0000000 --- a/Action20-35 +++ /dev/null @@ -1 +0,0 @@ - diff --git a/StreamExtensions.cs b/StreamExtensions.cs index 9f5bb25..9d52049 100644 --- a/StreamExtensions.cs +++ b/StreamExtensions.cs @@ -25,6 +25,514 @@ namespace System.IO { +#if NET20 + public static class StreamExtensions { + public static Task GetRequestStreamAsync( WebRequest request) { + return Task.Factory.FromAsync(request.BeginGetRequestStream, request.EndGetRequestStream, null); + } + + public static Task GetResponseAsync( WebRequest request) { + return Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null); + } + + public static void CopyTo( Stream source, Stream destination) { + CopyTo(source, destination, 16 * 1024); + } + + public static void CopyTo( Stream source, Stream destination, int bufferSize) { + if(destination == null) + throw new ArgumentNullException("destination"); + if(!source.CanRead) + throw new NotSupportedException("This stream does not support reading"); + if(!destination.CanWrite) + throw new NotSupportedException("This destination stream does not support writing"); + if(bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + + var buffer = new byte[bufferSize]; + int nread; + while((nread = source.Read(buffer, 0, bufferSize)) != 0) + destination.Write(buffer, 0, nread); + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream. + /// + /// + /// Copying begins at the current position in . + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync( Stream stream, Stream destination) { +#if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination); +#else + return CopyToAsync(stream, destination, 16 * 1024, CancellationToken.None); +#endif + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream, + /// using a specified buffer size. + /// + /// + /// Copying begins at the current position in . + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920. + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative or zero. + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync( Stream stream, Stream destination, int bufferSize) { +#if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination, bufferSize); +#else + return CopyToAsync(stream, destination, bufferSize, CancellationToken.None); +#endif + } + + /// + /// Asynchronously reads the bytes from a source stream and writes them to a destination stream, + /// using a specified buffer size and cancellation token. + /// + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// Copying begins at the current position in . + /// + /// + /// The source stream. + /// The stream to which the contents of the source stream will be copied. + /// The size, in bytes, of the buffer. This value must be greater than zero. The default size is 81920. + /// The token to monitor for cancellation requests. The default value is . + /// A task that represents the asynchronous copy operation. + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative or zero. + /// + /// + /// If is disposed. + /// -or- + /// If is disposed. + /// + /// + /// If does not support reading. + /// -or- + /// If does not support writing. + /// + public static Task CopyToAsync( Stream stream, Stream destination, int bufferSize, CancellationToken cancellationToken) { + if(stream == null) + throw new ArgumentNullException("stream"); + if(destination == null) + throw new ArgumentNullException("destination"); + if(!stream.CanRead) + throw new NotSupportedException("The stream does not support reading"); + if(!destination.CanWrite) + throw new NotSupportedException("The destination does not support writing"); + if(bufferSize <= 0) + throw new ArgumentOutOfRangeException("bufferSize"); + + if(cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + +#if NET45PLUS + // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.CopyToAsync(destination, bufferSize, cancellationToken); +#else + return CopyToAsync(stream, destination, new byte[bufferSize], cancellationToken); +#endif + } + + + +#if !NET45PLUS +#if UNITY + private static Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) + { + int bytesRead; + while ((bytesRead = ReadAsync(stream, buffer, 0, buffer.Length, cancellationToken).Await()) != 0) + { + destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).Await(); + } + + return Task.FromResult(true); + } +#elif NET20 + class AsyncState_Stream { + public byte[] buf; + public int bufferSize; + public Stream stream; + /// + /// 对buf的读取数值 + /// + public Action onAsyncRead; + } + static void onReadStreamAsync(IAsyncResult asyncResult) { + AsyncState_Stream ass = asyncResult.AsyncState as AsyncState_Stream; + Stream fs = ass.stream; + byte[] data = ass.buf; + int bufferSize = ass.bufferSize; + int bytesRead = fs.EndRead(asyncResult); + //输出到工作台 + //Console.Write(Encoding.ASCII.GetString(data, 0, bytesRead)); + //不断循环,直到读取完毕 + if(bytesRead > 0) { + if(ass.onAsyncRead != null) { + ass.onAsyncRead(ass, bytesRead); + } + fs.BeginRead(data, 0, bufferSize, onReadStreamAsync, ass); + } + else { + // fs.Close(); //当全部读取完毕,显式释放资源 + if(ass.onAsyncRead != null) { + ass.onAsyncRead(ass, 0); + } + } + } + private static Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) { + + int bytesRead; + while((bytesRead = TaskExtensions.Await(ReadAsync(stream, buffer, 0, buffer.Length, cancellationToken)) ) != 0) { + TaskExtensions.Await(WriteAsync(destination, buffer, 0, bytesRead, cancellationToken) ); + } + return Task.FromResult(true); + // + TaskCompletionSource ts = new TaskCompletionSource(); + //异步读 + AsyncState_Stream ass = new AsyncState_Stream() { + buf = buffer, + bufferSize = buffer.Length, + stream = stream + }; + ass.onAsyncRead = (ret, br) => { + bytesRead = br; + if(br == 0) { + ts.SetResult(true); + } + else { + destination.Write(ret.buf, 0, bytesRead); + } + + }; + AsyncCallback callback = new AsyncCallback(onReadStreamAsync); + IAsyncResult async = stream.BeginRead(buffer, 0, buffer.Length, callback, ass); + return ts.Task; + } +#else + + private static async Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) { + int bytesRead; + while((bytesRead = await ReadAsync(stream, buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) { + await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); + } + } + +#endif +#endif + + /// + /// Asynchronously clears all buffers for a stream and causes any buffered data to be written to the underlying device. + /// + /// + /// If a derived class does not flush the buffer in its implementation of the method, + /// the method will not flush the buffer. + /// + /// The stream to flush. + /// A task that represents the asynchronous flush operation. + /// If is . + /// If has been disposed. + public static Task FlushAsync( Stream stream) { +#if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.FlushAsync(); +#else + return FlushAsync(stream, CancellationToken.None); +#endif + } + + /// + /// Asynchronously clears all buffers for a stream and causes any buffered data to be written to the underlying device, + /// and monitors cancellation requests. + /// + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// If a derived class does not flush the buffer in its implementation of the method, + /// the method will not flush the buffer. + /// + /// + /// The stream to flush. + /// The token to monitor for cancellation requests. The default value is . + /// A task that represents the asynchronous flush operation. + /// If is . + /// If has been disposed. + public static Task FlushAsync( Stream stream, CancellationToken cancellationToken) { + if(stream == null) + throw new ArgumentNullException("stream"); + + if(cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + +#if NET45PLUS + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.FlushAsync(cancellationToken); +#else + return Task.Factory.StartNew(state => ((Stream)state).Flush(), stream, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); +#endif + } + + /// + /// Asynchronously reads a sequence of bytes from a stream and advances the position within the stream by the number of bytes read. + /// + /// + /// Use the property to determine whether the stream instance supports reading. + /// + /// The stream to read data from. + /// The buffer to write the data into. + /// The byte offset in at which to begin writing data from the stream. + /// The maximum number of bytes to read. + /// + /// A task that represents the asynchronous read operation. When the task completes successfully, the + /// property contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if + /// the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support reading. + /// If has been disposed. + /// If is currently in use by a previous read operation. + public static Task ReadAsync( Stream stream, byte[] buffer, int offset, int count) { +#if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.ReadAsync(buffer, offset, count); +#else + return ReadAsync(stream, buffer, offset, count, CancellationToken.None); +#endif + } + + /// + /// Asynchronously reads a sequence of bytes from a stream, advances the position within the stream by the number of bytes read, + /// and monitors cancellation requests. + /// + /// + /// Use the property to determine whether the stream instance supports reading. + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// + /// The stream to read data from. + /// The buffer to write the data into. + /// The byte offset in at which to begin writing data from the stream. + /// The maximum number of bytes to read. + /// The token to monitor for cancellation requests. The default value is . + /// + /// A task that represents the asynchronous read operation. When the task completes successfully, the + /// property contains the total number of bytes read into the buffer. The result value can be less than the number of bytes requested if + /// the number of bytes currently available is less than the requested number, or it can be 0 (zero) if the end of the stream has been reached. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support reading. + /// If has been disposed. + /// If is currently in use by a previous read operation. + public static Task ReadAsync( Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + if(stream == null) + throw new ArgumentNullException("stream"); + + if(cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + +#if NET45PLUS + // This code requires the `Stream` class provide an implementation of `ReadAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.ReadAsync(buffer, offset, count, cancellationToken); +#else + return Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, TaskCreationOptions.None); +#endif + } + + /// + /// Asynchronously writes a sequence of bytes to a stream and advances the position within the stream by the number of bytes written. + /// + /// + /// Use the property to determine whether the stream instance supports writing. + /// + /// The stream to write data to. + /// The buffer to read the data from. + /// The zero-based byte offset in buffer from which to begin copying bytes to the stream. + /// The maximum number of bytes to write. + /// + /// A task that represents the asynchronous write operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support writing. + /// If has been disposed. + /// If is currently in use by a previous write operation. + public static Task WriteAsync( Stream stream, byte[] buffer, int offset, int count) { +#if NET45PLUS + if (stream == null) + throw new ArgumentNullException("stream"); + + // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.WriteAsync(buffer, offset, count); +#else + return WriteAsync(stream, buffer, offset, count, CancellationToken.None); +#endif + } + + /// + /// Asynchronously writes a sequence of bytes to a stream, advances the position within the stream by the number of bytes written, + /// and monitors cancellation requests. + /// + /// + /// Use the property to determine whether the stream instance supports writing. + /// + /// If the operation is canceled before it completes, the returned task contains the + /// value for the property. + /// + /// + /// The stream to write data to. + /// The buffer to read the data from. + /// The zero-based byte offset in buffer from which to begin copying bytes to the stream. + /// The maximum number of bytes to write. + /// The token to monitor for cancellation requests. The default value is . + /// + /// A task that represents the asynchronous write operation. + /// + /// + /// If is . + /// -or- + /// If is . + /// + /// + /// If is negative. + /// -or- + /// If is negative. + /// + /// + /// If the sum of and is larger than the buffer length. + /// + /// If does not support writing. + /// If has been disposed. + /// If is currently in use by a previous write operation. + public static Task WriteAsync( Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + if(stream == null) + throw new ArgumentNullException("stream"); + + if(cancellationToken.IsCancellationRequested) + return GetCanceledTask(); + +#if NET45PLUS + // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will + // detect any case where this results in a stack overflow. + return stream.WriteAsync(buffer, offset, count, cancellationToken); +#else + return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, count, null); +#endif + } + + private static Task GetCanceledTask() { + var tcs = new TaskCompletionSource(); + tcs.SetCanceled(); + return tcs.Task; + } + } +#else public static class StreamExtensions { public static Task GetRequestStreamAsync(this WebRequest request) @@ -85,16 +593,16 @@ public static void CopyTo (this Stream source, Stream destination, int bufferSiz /// public static Task CopyToAsync(this Stream stream, Stream destination) { - #if NET45PLUS +#if NET45PLUS if (stream == null) throw new ArgumentNullException("stream"); // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.CopyToAsync(destination); - #else +#else return CopyToAsync(stream, destination, 16 * 1024, CancellationToken.None); - #endif +#endif } /// @@ -128,16 +636,16 @@ public static Task CopyToAsync(this Stream stream, Stream destination) /// public static Task CopyToAsync(this Stream stream, Stream destination, int bufferSize) { - #if NET45PLUS +#if NET45PLUS if (stream == null) throw new ArgumentNullException("stream"); // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.CopyToAsync(destination, bufferSize); - #else +#else return CopyToAsync(stream, destination, bufferSize, CancellationToken.None); - #endif +#endif } /// @@ -190,19 +698,19 @@ public static Task CopyToAsync(this Stream stream, Stream destination, int buffe if (cancellationToken.IsCancellationRequested) return GetCanceledTask(); - #if NET45PLUS +#if NET45PLUS // This code requires the `Stream` class provide an implementation of `CopyToAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.CopyToAsync(destination, bufferSize, cancellationToken); - #else +#else return CopyToAsync(stream, destination, new byte[bufferSize], cancellationToken); - #endif +#endif } - #if !NET45PLUS - #if UNITY +#if !NET45PLUS +#if UNITY private static Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) { int bytesRead; @@ -214,7 +722,7 @@ private static Task CopyToAsync(Stream stream, Stream destination, byte[] buffer return Task.FromResult(true); } - #else +#else private static async Task CopyToAsync(Stream stream, Stream destination, byte[] buffer, CancellationToken cancellationToken) { @@ -225,8 +733,8 @@ private static async Task CopyToAsync(Stream stream, Stream destination, byte[] } } - #endif - #endif +#endif +#endif /// /// Asynchronously clears all buffers for a stream and causes any buffered data to be written to the underlying device. @@ -241,16 +749,16 @@ private static async Task CopyToAsync(Stream stream, Stream destination, byte[] /// If has been disposed. public static Task FlushAsync(this Stream stream) { - #if NET45PLUS +#if NET45PLUS if (stream == null) throw new ArgumentNullException("stream"); // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.FlushAsync(); - #else +#else return FlushAsync(stream, CancellationToken.None); - #endif +#endif } /// @@ -278,13 +786,13 @@ public static Task FlushAsync(this Stream stream, CancellationToken cancellation if (cancellationToken.IsCancellationRequested) return GetCanceledTask(); - #if NET45PLUS +#if NET45PLUS // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.FlushAsync(cancellationToken); - #else +#else return Task.Factory.StartNew(state => ((Stream)state).Flush(), stream, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); - #endif +#endif } /// @@ -320,16 +828,16 @@ public static Task FlushAsync(this Stream stream, CancellationToken cancellation /// If is currently in use by a previous read operation. public static Task ReadAsync(this Stream stream, byte[] buffer, int offset, int count) { - #if NET45PLUS +#if NET45PLUS if (stream == null) throw new ArgumentNullException("stream"); // This code requires the `Stream` class provide an implementation of `FlushAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.ReadAsync(buffer, offset, count); - #else +#else return ReadAsync(stream, buffer, offset, count, CancellationToken.None); - #endif +#endif } /// @@ -377,13 +885,13 @@ public static Task ReadAsync(this Stream stream, byte[] buffer, int offset, if (cancellationToken.IsCancellationRequested) return GetCanceledTask(); - #if NET45PLUS +#if NET45PLUS // This code requires the `Stream` class provide an implementation of `ReadAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.ReadAsync(buffer, offset, count, cancellationToken); - #else +#else return Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, TaskCreationOptions.None); - #endif +#endif } /// @@ -417,16 +925,16 @@ public static Task ReadAsync(this Stream stream, byte[] buffer, int offset, /// If is currently in use by a previous write operation. public static Task WriteAsync(this Stream stream, byte[] buffer, int offset, int count) { - #if NET45PLUS +#if NET45PLUS if (stream == null) throw new ArgumentNullException("stream"); // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.WriteAsync(buffer, offset, count); - #else +#else return WriteAsync(stream, buffer, offset, count, CancellationToken.None); - #endif +#endif } /// @@ -472,13 +980,13 @@ public static Task WriteAsync(this Stream stream, byte[] buffer, int offset, int if (cancellationToken.IsCancellationRequested) return GetCanceledTask(); - #if NET45PLUS +#if NET45PLUS // This code requires the `Stream` class provide an implementation of `WriteAsync`. The unit tests will // detect any case where this results in a stack overflow. return stream.WriteAsync(buffer, offset, count, cancellationToken); - #else +#else return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, count, null); - #endif +#endif } private static Task GetCanceledTask() @@ -488,5 +996,6 @@ private static Task GetCanceledTask() return tcs.Task; } } +#endif } diff --git a/System.Threading.Tasks.Net20.csproj b/System.Threading.Tasks.Net20.csproj index ff1996d..87fb19e 100644 --- a/System.Threading.Tasks.Net20.csproj +++ b/System.Threading.Tasks.Net20.csproj @@ -22,7 +22,7 @@ 4 False True - x86 + AnyCPU True @@ -39,6 +39,7 @@ + diff --git a/System.Threading.Tasks.Net20.sln b/System.Threading.Tasks.Net20.sln new file mode 100644 index 0000000..17e4f93 --- /dev/null +++ b/System.Threading.Tasks.Net20.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Net20", "System.Threading.Tasks.Net20.csproj", "{DCB5D745-525C-46A1-BFC0-E12F87AB6165}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Net35", "System.Threading.Tasks.Net35.csproj", "{F1D8592C-3CCD-4844-81AA-BBE0700A43E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Unity", "System.Threading.Tasks.Unity.csproj", "{3264D50E-0161-4F46-A7EF-C487E43137E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Net20.Test", "Test\System.Threading.Tasks.Net20.Test\System.Threading.Tasks.Net20.Test.csproj", "{B4C1D9DE-12ED-4ADC-8943-8FC6E777C389}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCB5D745-525C-46A1-BFC0-E12F87AB6165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCB5D745-525C-46A1-BFC0-E12F87AB6165}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCB5D745-525C-46A1-BFC0-E12F87AB6165}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCB5D745-525C-46A1-BFC0-E12F87AB6165}.Release|Any CPU.Build.0 = Release|Any CPU + {F1D8592C-3CCD-4844-81AA-BBE0700A43E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1D8592C-3CCD-4844-81AA-BBE0700A43E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1D8592C-3CCD-4844-81AA-BBE0700A43E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1D8592C-3CCD-4844-81AA-BBE0700A43E5}.Release|Any CPU.Build.0 = Release|Any CPU + {3264D50E-0161-4F46-A7EF-C487E43137E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3264D50E-0161-4F46-A7EF-C487E43137E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3264D50E-0161-4F46-A7EF-C487E43137E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3264D50E-0161-4F46-A7EF-C487E43137E8}.Release|Any CPU.Build.0 = Release|Any CPU + {B4C1D9DE-12ED-4ADC-8943-8FC6E777C389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4C1D9DE-12ED-4ADC-8943-8FC6E777C389}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4C1D9DE-12ED-4ADC-8943-8FC6E777C389}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4C1D9DE-12ED-4ADC-8943-8FC6E777C389}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/System.Threading.Tasks.Unity.csproj b/System.Threading.Tasks.Unity.csproj index b5df6e0..0932866 100644 --- a/System.Threading.Tasks.Unity.csproj +++ b/System.Threading.Tasks.Unity.csproj @@ -3,10 +3,10 @@ Debug AnyCPU - {DCB5D745-525C-46A1-BFC0-E12F87AB6165} + {3264D50E-0161-4F46-A7EF-C487E43137E8} Library System.Threading.Tasks.Net35 - System.Threading.Tasks.Net35 + System.Threading.Tasks.Net35Unity v3.5 1.1 False @@ -34,6 +34,7 @@ true + diff --git a/System.Threading.Tasks.Unity.csproj.user b/System.Threading.Tasks.Unity.csproj.user new file mode 100644 index 0000000..ca1d04b --- /dev/null +++ b/System.Threading.Tasks.Unity.csproj.user @@ -0,0 +1,6 @@ + + + + ProjectFiles + + \ No newline at end of file diff --git a/System.Threading.Tasks/TaskExtensions.cs b/System.Threading.Tasks/TaskExtensions.cs index 07d1fda..0cb0630 100644 --- a/System.Threading.Tasks/TaskExtensions.cs +++ b/System.Threading.Tasks/TaskExtensions.cs @@ -45,6 +45,21 @@ public static Task Unwrap(Task task) { return TaskExtensionsImpl.Unwrap(task); } + + public static T Await( Task t) { + using(var mre = new ManualResetEventSlim()) { + t.ConfigureAwait(false).GetAwaiter().OnCompleted(mre.Set); + mre.Wait(); + return t.Result; + } + } + + public static void Await( Task t) { + using(var mre = new ManualResetEventSlim()) { + t.ConfigureAwait(false).GetAwaiter().OnCompleted(mre.Set); + mre.Wait(); + } + } } #else public static class TaskExtensions diff --git a/Test/System.Threading.Tasks.Net20.Test/Program.cs b/Test/System.Threading.Tasks.Net20.Test/Program.cs new file mode 100644 index 0000000..0c186a9 --- /dev/null +++ b/Test/System.Threading.Tasks.Net20.Test/Program.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +namespace System.Threading.Tasks.Net20.Test { + class Program { + static void Main(string[] args) { + byte[] buf1 = new byte[1024]; + int index = 0; + for(int i = 0; i < 16; i++) { + for(int j = 0; j < 64; j++) { + buf1[index] = (byte)j; + index++; + } + } + MemoryStream ms1 = new MemoryStream(1024 * 1024 * 100); + for(int i = 0; i < 1024 * 100; i++) { + ms1.Write(buf1, 0, buf1.Length); + } + ms1.Position = 0; + Console.WriteLine("do Task start:" + ms1.Length); + MemoryStream ms2 = new MemoryStream(1024); + var task = StreamExtensions.CopyToAsync(ms1, ms2, 1024); + //while(task.IsCompleted == false) { + Console.WriteLine("do Task:"+ms2.Length); + //} + task.Wait(); + Console.WriteLine("do Task end:"+ms2.Length); + Console.ReadLine(); + } + } +} diff --git a/Test/System.Threading.Tasks.Net20.Test/Properties/AssemblyInfo.cs b/Test/System.Threading.Tasks.Net20.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ef1b014 --- /dev/null +++ b/Test/System.Threading.Tasks.Net20.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("System.Threading.Tasks.Net20.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("System.Threading.Tasks.Net20.Test")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +//将 ComVisible 设置为 false 将使此程序集中的类型 +//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("b4c1d9de-12ed-4adc-8943-8fc6e777c389")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Test/System.Threading.Tasks.Net20.Test/System.Threading.Tasks.Net20.Test.csproj b/Test/System.Threading.Tasks.Net20.Test/System.Threading.Tasks.Net20.Test.csproj new file mode 100644 index 0000000..da13f70 --- /dev/null +++ b/Test/System.Threading.Tasks.Net20.Test/System.Threading.Tasks.Net20.Test.csproj @@ -0,0 +1,61 @@ + + + + + Debug + AnyCPU + {B4C1D9DE-12ED-4ADC-8943-8FC6E777C389} + Exe + Properties + System.Threading.Tasks.Net20.Test + System.Threading.Tasks.Net20.Test + v2.0 + 512 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + {dcb5d745-525c-46a1-bfc0-e12f87ab6165} + System.Threading.Tasks.Net20 + + + + + \ No newline at end of file diff --git a/Test/System.Threading.Tasks.Net20.Test/app.config b/Test/System.Threading.Tasks.Net20.Test/app.config new file mode 100644 index 0000000..2fa6e95 --- /dev/null +++ b/Test/System.Threading.Tasks.Net20.Test/app.config @@ -0,0 +1,3 @@ + + + From 5bfdb897b0b5e59f73e1b186fb0347522aa93022 Mon Sep 17 00:00:00 2001 From: RainsSoft Date: Tue, 19 Oct 2021 11:43:50 +0800 Subject: [PATCH 10/10] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4e13c9a..1638edf 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # dotnet-tpl20 +System.Threading.Tasks A backport of the Task Parallel Library to .NET 2.0 dotnet.20支持dotnet4.0的Task