csharp-sdk-upm/Storage/Source/Internal/Utilities/InternalExtensions.cs

106 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
/// <summary>
/// Provides helper methods that allow us to use terser code elsewhere.
/// </summary>
public static class InternalExtensions {
/// <summary>
/// Ensures a task (even null) is awaitable.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="task"></param>
/// <returns></returns>
public static Task<T> Safe<T>(this Task<T> task) {
return task ?? Task.FromResult<T>(default(T));
}
/// <summary>
/// Ensures a task (even null) is awaitable.
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
public static Task Safe(this Task task) {
return task ?? Task.FromResult<object>(null);
}
public delegate void PartialAccessor<T>(ref T arg);
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> self,
TKey key,
TValue defaultValue) {
TValue value;
if (self.TryGetValue(key, out value)) {
return value;
}
return defaultValue;
}
public static bool CollectionsEqual<T>(this IEnumerable<T> a, IEnumerable<T> b) {
return Object.Equals(a, b) ||
(a != null && b != null &&
a.SequenceEqual(b));
}
public static Task<TResult> OnSuccess<TIn, TResult>(this Task<TIn> task,
Func<Task<TIn>, TResult> continuation) {
return ((Task)task).OnSuccess(t => continuation((Task<TIn>)t));
}
public static Task OnSuccess<TIn>(this Task<TIn> task, Action<Task<TIn>> continuation) {
return task.OnSuccess((Func<Task<TIn>, object>)(t => {
continuation(t);
return null;
}));
}
public static Task<TResult> OnSuccess<TResult>(this Task task,
Func<Task, TResult> continuation) {
return task.ContinueWith(t => {
if (t.IsFaulted) {
var ex = t.Exception.Flatten();
if (ex.InnerExceptions.Count == 1) {
ExceptionDispatchInfo.Capture(ex.InnerExceptions[0]).Throw();
} else {
ExceptionDispatchInfo.Capture(ex).Throw();
}
// Unreachable
return Task.FromResult(default(TResult));
} else if (t.IsCanceled) {
var tcs = new TaskCompletionSource<TResult>();
tcs.SetCanceled();
return tcs.Task;
} else {
return Task.FromResult(continuation(t));
}
}).Unwrap();
}
public static Task OnSuccess(this Task task, Action<Task> continuation) {
return task.OnSuccess((Func<Task, object>)(t => {
continuation(t);
return null;
}));
}
public static Task WhileAsync(Func<Task<bool>> predicate, Func<Task> body) {
Func<Task> iterate = null;
iterate = () => {
return predicate().OnSuccess(t => {
if (!t.Result) {
return Task.FromResult(0);
}
return body().OnSuccess(_ => iterate()).Unwrap();
}).Unwrap();
};
return iterate();
}
}
}