mirror of
https://github.com/AlexMacocian/SystemExtensions.git
synced 2026-07-24 03:56:27 +00:00
Added various extensions.
Added coding style helpers. Unit tests.
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
using System.IO;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class BytesExtensions
|
||||
{
|
||||
public static byte[] ReadAllBytes(this Stream stream)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
var buffer = new byte[256];
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, 0, 256)) > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, read);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class CastExtensions
|
||||
{
|
||||
public static int Floor(this double value)
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
|
||||
public static int Ceiling(this double value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
|
||||
public static int Round(this double value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
|
||||
public static int Floor(this float value)
|
||||
{
|
||||
return (int)Math.Floor(value);
|
||||
}
|
||||
|
||||
public static int Ceiling(this float value)
|
||||
{
|
||||
return (int)Math.Ceiling(value);
|
||||
}
|
||||
|
||||
public static int Round(this float value)
|
||||
{
|
||||
return (int)Math.Round(value);
|
||||
}
|
||||
|
||||
public static int ToInt(this double value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this float value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
|
||||
public static int ToInt(this decimal value)
|
||||
{
|
||||
return (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class LinqExtensions
|
||||
{
|
||||
public static bool None<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
|
||||
{
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
predicate.ThrowIfNull(nameof(predicate));
|
||||
|
||||
return !enumerable.Any(predicate);
|
||||
}
|
||||
|
||||
public static bool None<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
enumerable.ThrowIfNull(nameof(enumerable));
|
||||
|
||||
return !enumerable.Any();
|
||||
}
|
||||
|
||||
public static ICollection<T> ClearAnd<T>(this ICollection<T> collection)
|
||||
{
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
|
||||
collection.Clear();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static ICollection<T> AddRange<T>(this ICollection<T> collection, IEnumerable<T> values)
|
||||
{
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
if (values is null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
foreach(var item in values)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static int IndexOfWhere<T>(this ICollection<T> collection, Func<T, bool> selector)
|
||||
{
|
||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||
if (selector is null) throw new ArgumentNullException(nameof(selector));
|
||||
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
{
|
||||
if (selector(item))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static T Cast<T>(this object obj)
|
||||
{
|
||||
return (T)obj;
|
||||
}
|
||||
|
||||
public static T As<T>(this object obj) where T : class
|
||||
{
|
||||
return obj as T;
|
||||
}
|
||||
|
||||
public static Optional<T> ToOptional<T>(this T obj)
|
||||
{
|
||||
return Optional.FromValue(obj);
|
||||
}
|
||||
|
||||
public static T ThrowIfNull<T>([ValidatedNotNull] this T obj, string name) where T : class
|
||||
{
|
||||
if (obj is null) throw new ArgumentNullException(name);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter)]
|
||||
sealed class ValidatedNotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class Optional
|
||||
{
|
||||
public static Optional<T> None<T>()
|
||||
{
|
||||
return new Optional<T>.None();
|
||||
}
|
||||
|
||||
public static Optional<T> FromValue<T>(T value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return new Optional<T>.None();
|
||||
}
|
||||
|
||||
return new Optional<T>.Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Optional<T> : IEquatable<Optional<T>>
|
||||
{
|
||||
public Optional(T value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
private T Value { get; }
|
||||
|
||||
public T ExtractValue()
|
||||
{
|
||||
if (this is None)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
public Optional<T> Do(Action<T> onSome, Action onNone)
|
||||
{
|
||||
if (onSome is null) throw new ArgumentNullException(nameof(onSome));
|
||||
if (onNone is null) throw new ArgumentNullException(nameof(onNone));
|
||||
|
||||
if (this is Some)
|
||||
{
|
||||
onSome.Invoke(this.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNone.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Optional<T> DoAny(Action<T> onSome = null, Action onNone = null)
|
||||
{
|
||||
if (this is Some)
|
||||
{
|
||||
onSome?.Invoke(this.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNone?.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Optional<V> Switch<V>(Func<T, V> onSome, Func<V> onNone)
|
||||
{
|
||||
if (onSome is null) throw new ArgumentNullException($"{nameof(onSome)}");
|
||||
if (onNone is null) throw new ArgumentNullException($"{nameof(onNone)}");
|
||||
|
||||
if (this is Some)
|
||||
{
|
||||
return Optional.FromValue(onSome.Invoke(this.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Optional.FromValue(onNone.Invoke());
|
||||
}
|
||||
}
|
||||
public Optional<V> SwitchAny<V>(Func<T, V> onSome = null, Func<V> onNone = null)
|
||||
{
|
||||
if (this is Some)
|
||||
{
|
||||
return onSome != null ? Optional.FromValue(onSome.Invoke(this.Value)) : Optional.FromValue(default(V));
|
||||
}
|
||||
else
|
||||
{
|
||||
return onNone != null ? Optional.FromValue(onNone.Invoke()) : Optional.FromValue(default(V));
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Optional<T>)
|
||||
{
|
||||
return this.Equals(obj);
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool Equals(Optional<T> other)
|
||||
{
|
||||
if (this is Some && other is Some)
|
||||
{
|
||||
return this.As<Some>().Equals(other.As<Some>());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static implicit operator Optional<T>(T value)
|
||||
{
|
||||
return Optional.FromValue(value);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value == null ? base.GetHashCode() : this.Value.GetHashCode();
|
||||
}
|
||||
|
||||
internal class Some : Optional<T>, IEquatable<Some>
|
||||
{
|
||||
public Some(T value) : base(value)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Some)
|
||||
{
|
||||
return this.Equals(obj.As<Some>());
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool Equals(Some other)
|
||||
{
|
||||
if (other is None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other is Some)
|
||||
{
|
||||
return this.Value.Equals(other.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator ==(Some left, Some right)
|
||||
{
|
||||
return left?.Equals(right) == true;
|
||||
}
|
||||
|
||||
public static bool operator !=(Some left, Some right)
|
||||
{
|
||||
return left?.Equals(right) != true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.Value is object ? this.Value.GetHashCode() : this.As<object>().GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
internal class None : Optional<T>
|
||||
{
|
||||
public None() : base(default)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
namespace System.Extensions
|
||||
{
|
||||
public class Result<TSuccess, TFailure>
|
||||
{
|
||||
private readonly object value;
|
||||
|
||||
public Result(TSuccess successValue)
|
||||
{
|
||||
value = successValue;
|
||||
}
|
||||
public Result(TFailure failureValue)
|
||||
{
|
||||
value = failureValue;
|
||||
}
|
||||
|
||||
public bool TryExtractSuccess(out TSuccess successValue)
|
||||
{
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
successValue = success;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
successValue = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool TryExtractFailure(out TFailure failureValue)
|
||||
{
|
||||
|
||||
if (value is TFailure failure)
|
||||
{
|
||||
failureValue = failure;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
failureValue = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public Result<TSuccess, TFailure> Do(Action onSuccess, Action onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess)
|
||||
{
|
||||
onSuccess.Invoke();
|
||||
}
|
||||
else if (value is TFailure)
|
||||
{
|
||||
onFailure.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> DoAny(Action onSuccess = null, Action onFailure = null)
|
||||
{
|
||||
if (value is TSuccess)
|
||||
{
|
||||
onSuccess?.Invoke();
|
||||
}
|
||||
else if (value is TFailure)
|
||||
{
|
||||
onFailure?.Invoke();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> Do(Action<TSuccess> onSuccess, Action<TFailure> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
onFailure.Invoke(failure);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Result<TSuccess, TFailure> DoAny(Action<TSuccess> onSuccess = null, Action<TFailure> onFailure = null)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
onSuccess?.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
onFailure?.Invoke(failure);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public T Switch<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return onFailure.Invoke(failure);
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
|
||||
}
|
||||
public T SwitchAny<T>(Func<TSuccess, T> onSuccess = null, Func<TFailure, T> onFailure = null)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return onSuccess is null ? default : onSuccess.Invoke(success);
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return onFailure is null ? default : onFailure.Invoke(failure);
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to {typeof(T)}");
|
||||
}
|
||||
public Result<V, K> Switch<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
|
||||
{
|
||||
if (onSuccess is null) throw new ArgumentNullException(nameof(onSuccess));
|
||||
|
||||
if (onFailure is null) throw new ArgumentNullException(nameof(onFailure));
|
||||
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return Result<V, K>.Success(onSuccess.Invoke(success));
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return Result<V, K>.Failure(onFailure.Invoke(failure));
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
|
||||
}
|
||||
public Result<V, K> SwitchAny<V, K>(Func<TSuccess, V> onSuccess, Func<TFailure, K> onFailure)
|
||||
{
|
||||
if (value is TSuccess success)
|
||||
{
|
||||
return Result<V, K>.Success(onSuccess is null ? default : onSuccess.Invoke(success));
|
||||
}
|
||||
else if (value is TFailure failure)
|
||||
{
|
||||
return Result<V, K>.Failure(onFailure is null ? default : onFailure.Invoke(failure));
|
||||
}
|
||||
throw new InvalidOperationException($"{nameof(value)} must be of type {typeof(TSuccess)} or {typeof(TFailure)} in order to switch to Result of type {typeof(V)} or {typeof(K)}");
|
||||
}
|
||||
public Optional<TSuccess> ToOptional()
|
||||
{
|
||||
if (value is TSuccess)
|
||||
{
|
||||
return Optional.FromValue(value.Cast<TSuccess>());
|
||||
}
|
||||
|
||||
return Optional.None<TSuccess>();
|
||||
}
|
||||
|
||||
public static implicit operator Result<TSuccess, TFailure>(TSuccess success)
|
||||
{
|
||||
return Success(success);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TSuccess, TFailure>(TFailure failure)
|
||||
{
|
||||
return Failure(failure);
|
||||
}
|
||||
|
||||
public static Result<TSuccess, TFailure> Success(TSuccess value)
|
||||
{
|
||||
return new Result<TSuccess, TFailure>(value);
|
||||
}
|
||||
public static Result<TSuccess, TFailure> Failure(TFailure value)
|
||||
{
|
||||
return new Result<TSuccess, TFailure>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.IO;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class StreamExtensions
|
||||
{
|
||||
public static void DoWhileReading(this Stream stream, Action<int, byte[]> action, int bufferLength = 256)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
if (action is null) throw new ArgumentNullException(nameof(action));
|
||||
|
||||
var buffer = new byte[bufferLength];
|
||||
var read = stream.Read(buffer, 0, bufferLength);
|
||||
while(read > 0)
|
||||
{
|
||||
action(bufferLength, buffer);
|
||||
read = stream.Read(buffer, 0, bufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
var buffer = new byte[count];
|
||||
stream.Read(buffer, 0, count);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static Stream Rewind(this Stream stream)
|
||||
{
|
||||
if (stream is null) throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
if (!stream.CanSeek) throw new InvalidOperationException("Stream doesn't support rewinding");
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Text;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static byte[] GetBytes(this string s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(s);
|
||||
}
|
||||
|
||||
public static string GetString(this byte[] bytes)
|
||||
{
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class TaskExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Result type.</typeparam>
|
||||
/// <param name="task">Task.</param>
|
||||
/// <returns>The started <see cref="Task{TResult}"/></returns>
|
||||
public static Task<T> LongRunning<T>(this Task<T> task)
|
||||
{
|
||||
return Task.Factory.StartNew(async () =>
|
||||
{
|
||||
return await task;
|
||||
}, TaskCreationOptions.LongRunning).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark task as <see cref="TaskCreationOptions.LongRunning"/>.
|
||||
/// </summary>
|
||||
/// <param name="task">Task.</param>
|
||||
/// <returns>The started <see cref="Task"/></returns>
|
||||
public static Task LongRunning(this Task task)
|
||||
{
|
||||
return Task.Factory.StartNew(async () =>
|
||||
{
|
||||
await task;
|
||||
}, TaskCreationOptions.LongRunning).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute action periodically and asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="onTick">Action to be executed.</param>
|
||||
/// <param name="dueTime">Time to pass before starting to execute.</param>
|
||||
/// <param name="interval">Interval between procs.</param>
|
||||
/// <param name="token">Cancellation token used to cancel the cycle.</param>
|
||||
/// <returns></returns>
|
||||
public static async Task RunPeriodicAsync(this Action onTick, TimeSpan dueTime, TimeSpan interval, CancellationToken token)
|
||||
{
|
||||
if (dueTime > TimeSpan.Zero)
|
||||
await Task.Delay(dueTime, token).ConfigureAwait(false);
|
||||
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
onTick?.Invoke();
|
||||
if (interval > TimeSpan.Zero)
|
||||
await Task.Delay(interval, token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute's an async Task<T> method which has a void return value synchronously
|
||||
/// </summary>
|
||||
/// <param name="task">Task<T> method to execute</param>
|
||||
public static void RunSync(this Func<Task> task)
|
||||
{
|
||||
var oldContext = SynchronizationContext.Current;
|
||||
var synch = new ExclusiveSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(synch);
|
||||
synch.Post(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await task();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
synch.InnerException = e;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
synch.EndMessageLoop();
|
||||
}
|
||||
}, null);
|
||||
synch.BeginMessageLoop();
|
||||
|
||||
SynchronizationContext.SetSynchronizationContext(oldContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute's an async Task<T> method which has a T return type synchronously
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return Type</typeparam>
|
||||
/// <param name="task">Task<T> method to execute</param>
|
||||
/// <returns></returns>
|
||||
public static T RunSync<T>(this Func<Task<T>> task)
|
||||
{
|
||||
var oldContext = SynchronizationContext.Current;
|
||||
var synch = new ExclusiveSynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(synch);
|
||||
T ret = default(T);
|
||||
synch.Post(async _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = await task();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
synch.InnerException = e;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
synch.EndMessageLoop();
|
||||
}
|
||||
}, null);
|
||||
synch.BeginMessageLoop();
|
||||
SynchronizationContext.SetSynchronizationContext(oldContext);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private class ExclusiveSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
private bool done;
|
||||
public Exception InnerException { get; set; }
|
||||
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
|
||||
readonly Queue<Tuple<SendOrPostCallback, object>> items =
|
||||
new Queue<Tuple<SendOrPostCallback, object>>();
|
||||
|
||||
public override void Send(SendOrPostCallback d, object state)
|
||||
{
|
||||
throw new NotSupportedException("We cannot send to our same thread");
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
lock (items)
|
||||
{
|
||||
items.Enqueue(Tuple.Create(d, state));
|
||||
}
|
||||
workItemsWaiting.Set();
|
||||
}
|
||||
|
||||
public void EndMessageLoop()
|
||||
{
|
||||
Post(_ => done = true, null);
|
||||
}
|
||||
|
||||
public void BeginMessageLoop()
|
||||
{
|
||||
while (!done)
|
||||
{
|
||||
Tuple<SendOrPostCallback, object> task = null;
|
||||
lock (items)
|
||||
{
|
||||
if (items.Count > 0)
|
||||
{
|
||||
task = items.Dequeue();
|
||||
}
|
||||
}
|
||||
if (task != null)
|
||||
{
|
||||
task.Item1(task.Item2);
|
||||
if (InnerException != null) // the method threw an exeption
|
||||
{
|
||||
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
workItemsWaiting.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override SynchronizationContext CreateCopy()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Extensions
|
||||
{
|
||||
public static class Try
|
||||
{
|
||||
public static Try<TResult> Action<TResult>(Func<TResult> act)
|
||||
{
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
}
|
||||
public class Try<TResult>
|
||||
{
|
||||
private readonly Func<TResult> action;
|
||||
private readonly List<Func<Exception, TResult>> catchActions = new List<Func<Exception, TResult>>();
|
||||
internal Try(Func<TResult> action)
|
||||
{
|
||||
this.action = action;
|
||||
}
|
||||
public static Try<TResult> Action(Func<TResult> act)
|
||||
{
|
||||
return new Try<TResult>(act);
|
||||
}
|
||||
|
||||
public Try<TResult> Catch<TException>(Func<TException, TResult> act) where TException : Exception
|
||||
{
|
||||
this.catchActions.Add((Func<Exception, TResult>)act);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TResult Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
return action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
{
|
||||
return catchAction(ex);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public TResult Finally(Action act)
|
||||
{
|
||||
if (act is null) throw new ArgumentNullException(nameof(act));
|
||||
|
||||
try
|
||||
{
|
||||
return this.action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
foreach (var catchAction in this.catchActions)
|
||||
{
|
||||
return catchAction(ex);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
act();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<RootNamespace>System</RootNamespace>
|
||||
<Version>1.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace SystemExtensions.Collections.Tests
|
||||
namespace System.Collections.Tests
|
||||
{
|
||||
[TestClass()]
|
||||
public class AVLTreeTests
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
|
||||
namespace System.Collections.Tests
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Extensions.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class OptionalTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SomeValueShouldEqualOptional()
|
||||
{
|
||||
var value = string.Empty;
|
||||
var optional = value.ToOptional();
|
||||
|
||||
Assert.IsTrue(optional.Equals(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromNullShouldNotEqual()
|
||||
{
|
||||
object value = null;
|
||||
var optional = value.ToOptional();
|
||||
|
||||
Assert.IsFalse(optional.Equals(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromValueShouldBeSome()
|
||||
{
|
||||
var optional = Optional.FromValue<object>(new object());
|
||||
|
||||
optional.DoAny(
|
||||
onNone: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OptionalFromNullShouldBeNone()
|
||||
{
|
||||
var optional = Optional.FromValue<object>(null);
|
||||
|
||||
optional.DoAny(
|
||||
onSome: _ => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
optional.Do(
|
||||
onSome: _ => { },
|
||||
onNone: () => throw new InvalidOperationException());
|
||||
|
||||
nullOptional.Do(
|
||||
onSome: _ => throw new InvalidOperationException(),
|
||||
onNone: () => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoAnyShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
optional.DoAny(
|
||||
onNone: () => throw new InvalidOperationException());
|
||||
|
||||
nullOptional.DoAny(
|
||||
onSome: _ => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
var newValue = optional.Switch(
|
||||
onSome: _ => string.Empty,
|
||||
onNone: () => throw new InvalidOperationException())
|
||||
.ExtractValue();
|
||||
|
||||
var newNullValue = nullOptional.Switch<string>(
|
||||
onSome: _ => throw new InvalidOperationException(),
|
||||
onNone: () => null)
|
||||
.ExtractValue();
|
||||
|
||||
newValue.Should().Be(string.Empty);
|
||||
newNullValue.Should().Be(null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchAnyShouldExecute()
|
||||
{
|
||||
var optional = Optional.FromValue(string.Empty);
|
||||
var nullOptional = Optional.FromValue<string>(null);
|
||||
|
||||
var newValue = optional.SwitchAny(
|
||||
onSome: _ => string.Empty)
|
||||
.ExtractValue();
|
||||
|
||||
var newNullValue = nullOptional.SwitchAny<string>(
|
||||
onNone: () => null)
|
||||
.ExtractValue();
|
||||
|
||||
newValue.Should().Be(string.Empty);
|
||||
newNullValue.Should().Be(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace System.Extensions.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class ResultTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void SuccessResultShouldCreateFromSuccess()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var result = Result<string, object>.Success(success);
|
||||
|
||||
result.DoAny(
|
||||
onFailure: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void FailureResultShouldCreateFromFailure()
|
||||
{
|
||||
var failure = new object();
|
||||
var result = Result<string, object>.Failure(failure);
|
||||
|
||||
result.DoAny(
|
||||
onSuccess: () => throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
successResult.Do(
|
||||
onSuccess: _ => { },
|
||||
onFailure: _ => throw new InvalidOperationException());
|
||||
|
||||
failedResult.Do(
|
||||
onSuccess: _ => throw new InvalidOperationException(),
|
||||
onFailure: _ => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DoAnyShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
successResult.DoAny(
|
||||
onSuccess: _ => { });
|
||||
|
||||
failedResult.DoAny(
|
||||
onFailure: _ => { });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successSwitch = successResult.Switch(
|
||||
onSuccess: _ => string.Empty,
|
||||
onFailure: _ => throw new InvalidOperationException());
|
||||
|
||||
var failedSwitch = failedResult.Switch(
|
||||
onSuccess: _ => throw new InvalidOperationException(),
|
||||
onFailure: _ => string.Empty);
|
||||
|
||||
success.Should().Be(failedSwitch);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SwitchAnyShouldExecute()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successSwitch = successResult.SwitchAny(
|
||||
onSuccess: _ => string.Empty);
|
||||
|
||||
var failedSwitch = failedResult.SwitchAny(
|
||||
onFailure: _ => string.Empty);
|
||||
|
||||
success.Should().Be(failedSwitch);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ToOptionalShouldConvert()
|
||||
{
|
||||
var success = string.Empty;
|
||||
var successResult = Result<string, object>.Success(success);
|
||||
|
||||
var failure = new object();
|
||||
var failedResult = Result<string, object>.Failure(failure);
|
||||
|
||||
var successOptional = successResult.ToOptional();
|
||||
var failureOptional = failedResult.ToOptional();
|
||||
|
||||
successOptional.Should().NotBeNull();
|
||||
failureOptional.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Structures.BitStructures;
|
||||
|
||||
namespace SystemExtensionsTests.Structures
|
||||
namespace System.Structures.BitStructures.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Int32BitStructTests
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Structures.BitStructures;
|
||||
|
||||
namespace SystemExtensionsTests.Structures
|
||||
namespace System.Structures.BitStructures.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Int64BitStructTests
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -39,14 +39,26 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FluentAssertions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FluentAssertions.6.0.0-alpha0002\lib\net47\FluentAssertions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.3\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.3\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0-preview.2.21154.6\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||
@@ -63,12 +75,15 @@
|
||||
<Compile Include="Collections\PriorityQueueTests.cs" />
|
||||
<Compile Include="Collections\SkipListTests.cs" />
|
||||
<Compile Include="Collections\TreapTests.cs" />
|
||||
<Compile Include="Extensions\OptionalTests.cs" />
|
||||
<Compile Include="Extensions\ResultTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Structures\Int32BitStructTests.cs" />
|
||||
<Compile Include="Structures\Int64BitStructTests.cs" />
|
||||
<Compile Include="Threading\PriorityThreadPoolTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -101,10 +116,10 @@
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.3\build\net45\MSTest.TestAdapter.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MSTest.TestAdapter" version="1.3.2" targetFramework="net461" />
|
||||
<package id="MSTest.TestFramework" version="1.3.2" targetFramework="net461" />
|
||||
<package id="FluentAssertions" version="6.0.0-alpha0002" targetFramework="net472" />
|
||||
<package id="MSTest.TestAdapter" version="2.2.3" targetFramework="net472" />
|
||||
<package id="MSTest.TestFramework" version="2.2.3" targetFramework="net472" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0-preview.2.21154.6" targetFramework="net472" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user