V1.2 新构架

This commit is contained in:
Aigio Liu
2021-02-20 16:45:44 +08:00
parent c2d95a1833
commit 4d76decf73
343 changed files with 41333 additions and 4 deletions
@@ -0,0 +1,26 @@
using System.Runtime.InteropServices;
// ReSharper disable once CheckNamespace
namespace System
{
public static class ByteArrayExtensions
{
public static sbyte[] ToSByteArray(this byte[] buffer)
{
ReadOnlySpan<byte> _buffer = buffer;
return _buffer.ToSByteArray();
}
public static sbyte[] ToSByteArray(this ReadOnlySpan<byte> buffer)
=> MemoryMarshal.Cast<byte, sbyte>(buffer).ToArray();
public static byte[] ToByteArray(this sbyte[] buffer)
{
ReadOnlySpan<sbyte> _buffer = buffer;
return _buffer.ToByteArray();
}
public static byte[] ToByteArray(this ReadOnlySpan<sbyte> buffer)
=> MemoryMarshal.Cast<sbyte, byte>(buffer).ToArray();
}
}
@@ -0,0 +1,30 @@
using System.Properties;
// ReSharper disable once CheckNamespace
namespace System
{
/// <summary>
/// Enum 扩展 <see cref="DayOfWeek"/>
/// </summary>
public static partial class DayOfWeekEnumExtensions
{
/// <summary>
/// 将 <see cref="DayOfWeek"/>(周) 转换为字符串
/// </summary>
/// <param name="dayOfWeek"></param>
/// <param name="format_short_or_long">使用[(<see langword="true"/>)短]或[(<see langword="false"/>)长]的格式,默认使用长格式</param>
/// <returns></returns>
public static string ToString2(this DayOfWeek dayOfWeek, bool format_short_or_long = false)
=> dayOfWeek switch
{
DayOfWeek.Monday => format_short_or_long ? SR.DayOfWeek_S1 : SR.DayOfWeek_L1,
DayOfWeek.Tuesday => format_short_or_long ? SR.DayOfWeek_S2 : SR.DayOfWeek_L2,
DayOfWeek.Wednesday => format_short_or_long ? SR.DayOfWeek_S3 : SR.DayOfWeek_L3,
DayOfWeek.Thursday => format_short_or_long ? SR.DayOfWeek_S4 : SR.DayOfWeek_L4,
DayOfWeek.Friday => format_short_or_long ? SR.DayOfWeek_S5 : SR.DayOfWeek_L5,
DayOfWeek.Saturday => format_short_or_long ? SR.DayOfWeek_S6 : SR.DayOfWeek_L6,
DayOfWeek.Sunday => format_short_or_long ? SR.DayOfWeek_S0 : SR.DayOfWeek_L0,
_ => throw new ArgumentOutOfRangeException(nameof(dayOfWeek), dayOfWeek, null),
};
}
}
@@ -0,0 +1,21 @@
// ReSharper disable once CheckNamespace
namespace System
{
public static partial class EnumExtensions
{
/// <summary>
/// 返回一个布尔值,该值指示给定的整数值或其名称字符串是否存在于指定的枚举中
/// </summary>
/// <param name="value"></param>
/// <returns>如果 enumType 中的某个常量的值等于 value,则为 <see langword="true"/>;否则为 <see langword="false"/></returns>
public static bool IsDefined(this Enum value) => Enum.IsDefined(value.GetType(), value);
public static TEnum ConvertToEnum<TEnum>(this int value)
where TEnum : struct, IConvertible
=> Enum2.ConvertToEnum<TEnum, int>(value);
public static int ConvertToInt32<TEnum>(this TEnum value)
where TEnum : struct, IConvertible
=> Enum2.ConvertToEnum<int, TEnum>(value);
}
}
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Properties;
// ReSharper disable once CheckNamespace
namespace System
{
public static class EnumerableExtensions
{
/// <summary>
/// 通过使用相应类型的默认相等比较器对序列的元素进行比较,以确定两个序列是否相等
/// </summary>
/// <typeparam name="TSource">输入序列中的元素的类型</typeparam>
/// <param name="first">一个用于比较 second 的 <see cref="IEnumerable{T}"/></param>
/// <param name="second">要与第一个序列进行比较的 <see cref="IEnumerable{T}"/></param>
/// <returns></returns>
public static bool SequenceEqual_Nullable<TSource>(this IEnumerable<TSource>? first, IEnumerable<TSource>? second)
{
if (first == null) return second == null;
if (second == null) return first == null;
return first.SequenceEqual(second);
}
/// <summary>
/// 确定序列是否包含任何元素
/// </summary>
/// <typeparam name="TSource">source 的元素类型</typeparam>
/// <param name="source">要检查是否为空的 <see cref="IEnumerable{T}"/></param>
/// <returns>如果源序列包含任何元素,则为 <see langword="true"/>;否则为 <see langword="false"/></returns>
public static bool Any_Nullable<TSource>(this IEnumerable<TSource>? source)
{
if (source == null) return false;
return source.Any();
}
/// <summary>
/// 确定序列是否包含任何元素(带条件)
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static bool Any_Nullable<TSource>(this IEnumerable<TSource>? source, Func<TSource, bool> predicate)
{
if (source == null) return false;
return source.Any(predicate);
}
public static Dictionary<TKey, TValue> ReverseKeyValue<TValue, TKey>(this IEnumerable<KeyValuePair<TValue, TKey>> source) where TKey : notnull
=> source.ToDictionary(k => k.Value, v => v.Key);
/// <inheritdoc cref="List{T}.AddRange(IEnumerable{T})"/>
public static void AddRange<T>(this IList<T> ts, IEnumerable<T> collection)
{
if (ts is List<T> list)
{
list.AddRange(collection);
}
else
{
if (ts.IsReadOnly) throw new NotSupportedException(SR.NotSupported_FixedSizeCollection);
var c = collection == ts ? collection.ToArray() : collection;
foreach (var item in c)
{
ts.Add(item);
}
}
}
}
}
@@ -0,0 +1,29 @@
using System.Threading.Tasks;
// ReSharper disable once CheckNamespace
namespace System
{
public static class ExceptionExtensions
{
/// <summary>
/// 是否为取消操作异常
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
public static bool IsCanceledException(this Exception e)
{
if (e is TaskCanceledException || e is OperationCanceledException)
{
return true;
}
if (DI.Platform == Platform.Android)
{
if (e.Message == "Canceled" && e.GetType().FullName == "Java.IO.IOException")
{
return true;
}
}
return false;
}
}
}
@@ -0,0 +1,88 @@
using System.Common;
// ReSharper disable once CheckNamespace
namespace System
{
public static class GuidExtensions
{
/// <summary>
/// 返回 <see cref="Guid"/> 结构的此实例值的字符串表示形式(格式N)
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
public static string ToStringN(this Guid guid) => guid.ToString(Constants.N);
/// <summary>
/// 返回 <see cref="Guid"/> 结构的此实例值的字符串表示形式(格式N)
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
public static string? ToStringN(this Guid? guid) => guid.HasValue ? guid.Value.ToStringN() : null;
static bool TryParseGuid_Format_D(string? input, out Guid result) => Guid.TryParse(input, out result);
static bool TryParseGuid_Format_N(string? input, out Guid result) => Guid.TryParseExact(input, Constants.N, out result);
static bool TryParseGuid(string? input, out Guid result, bool isFormatNFirst)
{
if (isFormatNFirst)
{
if (TryParseGuid_Format_N(input, out result))
{
return true;
}
else if (TryParseGuid_Format_D(input, out result))
{
return true;
}
return false;
}
else
{
if (TryParseGuid_Format_D(input, out result))
{
return true;
}
else if (TryParseGuid_Format_N(input, out result))
{
return true;
}
return false;
}
}
/// <summary>
/// 将包含 <see cref="Guid"/> 表示形式的指定只读字符范围转换为等效的 Guid 结构
/// <para>优先尝试使用格式D</para>
/// </summary>
/// <param name="input"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParseGuid(this string? input, out Guid result) => TryParseGuid(input, out result, false);
/// <summary>
/// 将包含 <see cref="Guid"/> 表示形式的指定只读字符范围转换为等效的 Guid 结构
/// <para>优先尝试使用格式D</para>
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static Guid? TryParseGuid(this string? input) => TryParseGuid(input, out var result) ? result : default;
/// <summary>
/// 将包含 <see cref="Guid"/> 表示形式的指定只读字符范围转换为等效的 Guid 结构
/// <para>优先尝试使用格式N</para>
/// </summary>
/// <param name="input"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool TryParseGuidN(this string? input, out Guid result) => TryParseGuid(input, out result, true);
/// <summary>
/// 将包含 <see cref="Guid"/> 表示形式的指定只读字符范围转换为等效的 Guid 结构
/// <para>优先尝试使用格式N</para>
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static Guid? TryParseGuidN(this string? input) => TryParseGuidN(input, out var result) ? result : default;
}
}
@@ -0,0 +1,24 @@
// ReSharper disable once CheckNamespace
namespace System
{
public static class ObjectExtensions
{
public static T ThrowIsNull<T>(this T? t, string parameterName) where T : class
{
if (t == null)
{
throw new ArgumentNullException(parameterName);
}
return t;
}
public static T ThrowIsNull<T>(this T? t, string parameterName) where T : struct
{
if (!t.HasValue)
{
throw new ArgumentNullException(parameterName);
}
return t.Value;
}
}
}
@@ -0,0 +1,19 @@
using Xamarin.Essentials;
// ReSharper disable once CheckNamespace
namespace System
{
/// <summary>
/// Enum 扩展 <see cref="PermissionStatus"/>
/// </summary>
public static class PermissionStatusEnumExtensions
{
/// <summary>
/// 权限是否已授予
/// </summary>
/// <param name="permissionStatus"></param>
/// <returns></returns>
public static bool IsOk(this PermissionStatus permissionStatus)
=> permissionStatus == PermissionStatus.Granted;
}
}
@@ -0,0 +1,63 @@
using System.IO;
using System.Linq;
using System.Reflection;
// ReSharper disable once CheckNamespace
namespace System
{
public static class ReflectionExtensions
{
const string TAG = "ReflectionEx";
/// <summary>
/// 检索应用于指定程序集的指定类型的自定义特性。
/// <para>如果发生 <see cref="FileNotFoundException"/> 将返回 <see langword="null"/></para>
/// </summary>
/// <param name="assembly"></param>
/// <param name="attrType"></param>
/// <returns></returns>
public static Attribute[]? GetCustomAttributesSafe(this Assembly assembly, Type attrType)
{
try
{
return assembly.GetCustomAttributes(attrType).ToArray();
}
catch (FileNotFoundException)
{
// Sometimes the previewer doesn't actually have everything required for these loads to work
Log.Warn(TAG, "Could not load assembly: {0} for Attribute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
}
return null;
}
public static T GetRequiredCustomAttribute<T>(this Assembly assembly) where T : Attribute
{
var requiredCustomAttribute = assembly.GetCustomAttribute<T>();
if (requiredCustomAttribute == null)
throw new NullReferenceException(nameof(requiredCustomAttribute));
return requiredCustomAttribute;
}
static bool IsNullableType(this Type t)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
/// <summary>
/// 类型是否为 <see cref="Nullable{T}"/> 可空类型
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
public static bool IsNullable(this Type t)
{
if (t.IsValueType) // 值类型(struct)进行可空判断
{
return IsNullableType(t);
}
return true; // 引用类型(class)都可空
}
public static bool IsStatic(this Type t) => t.IsAbstract && t.IsSealed;
}
}
@@ -0,0 +1,42 @@
// ReSharper disable once CheckNamespace
namespace System
{
public static partial class SingleExtensions
{
/// <summary>
/// (向下取整)返回小于或等于指定数字的最大整数值
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static int FloorToInt(this float f) => (int)MathF.Floor(f);
/// <summary>
/// (进一法)返回大于或等于指定数字的最小整数值
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static int CeilingToInt(this float f) => (int)MathF.Ceiling(f);
/// <summary>
/// 将值舍入到最接近的整数或指定的小数位数
/// </summary>
/// <param name="f"></param>
/// <param name="mode">在两个数字之间时如何舍入的规范</param>
/// <returns></returns>
public static int RoundToInt(this float f, MidpointRounding mode) => (int)MathF.Round(f, mode);
/// <summary>
/// (五舍六入)将值舍入到最接近的整数或指定的小数位数
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static int RoundToInt(this float f) => (int)MathF.Round(f);
/// <summary>
/// (四舍五入)将值舍入到最接近的整数或指定的小数位数
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static int Round2ToInt(this float f) => (int)MathF.Round(f, MidpointRounding.AwayFromZero);
}
}
@@ -0,0 +1,219 @@
using System.Collections.Generic;
using System.Linq;
// ReSharper disable once CheckNamespace
namespace System
{
public static partial class StringExtensions
{
#region System.String 内置函数增强型扩展(用于取代原有函数)
#region IndexOf
/// <summary>
/// 报告指定 Unicode 字符在此字符串中的第一个匹配项的从零开始的索引。
/// <para>注意:如果 value 仅为英文字符或数字符号,则使用原函数 <see cref="string.IndexOf(char)"/></para>
/// </summary>
/// <param name="str"></param>
/// <param name="value">要查找的 Unicode 字符。</param>
/// <returns>如果找到该字符,则为 value 的从零开始的索引位置;如果未找到,则为 -1。</returns>
public static int IndexOf_(this string str, char value) => DI.IsRunningOnMono ? str.IndexOf(value) : str.IndexOf(value, StringComparison.Ordinal);
/// <summary>
/// 报告指定 Unicode 字符在此字符串中的第一个匹配项的从零开始的索引。
/// <para>注意:如果 value 仅为英文字符或数字符号,则使用原函数 <see cref="string.IndexOf(char)"/></para>
/// </summary>
/// <param name="str"></param>
/// <param name="value">要查找的 Unicode 字符。</param>
/// <returns>如果找到该字符,则为 value 的从零开始的索引位置;如果未找到,则为 -1。</returns>
public static int IndexOf_Nullable(this string? str, char value)
{
if (str == null) return -1;
return IndexOf_(str, value);
}
/// <summary>
/// 报告指定字符串在此实例中的第一个匹配项的从零开始的索引。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要搜寻的字符串。</param>
/// <returns>如果找到该字符串,则为 value 的从零开始的索引位置;如果未找到该字符串,则为 -1。 如果 value 为 Empty,则返回值为 0。</returns>
public static int IndexOf_(this string str, string value) => str.IndexOf(value, StringComparison.Ordinal);
/// <summary>
/// 报告指定字符串在此实例中的第一个匹配项的从零开始的索引。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要搜寻的字符串。</param>
/// <returns>如果找到该字符串,则为 value 的从零开始的索引位置;如果未找到该字符串,则为 -1。 如果 value 为 Empty,则返回值为 0。</returns>
public static int IndexOf_Nullable(this string? str, string value)
{
if (str == null) return -1;
return IndexOf_(str, value);
}
#endregion
#region Contains
/// <summary>
/// 返回一个值,该值指示指定的字符是否出现在此字符串中。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要查找的字符。</param>
/// <returns>如果 value 参数在此字符串中出现,则为 true;否则为 false。</returns>
public static bool Contains_(this string str, char value) => str.Contains(value, StringComparison.Ordinal);
/// <summary>
/// 返回一个值,该值指示指定的字符是否出现在此字符串中。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要查找的字符。</param>
/// <returns>如果 value 参数在此字符串中出现,则为 true;否则为 false。</returns>
public static bool Contains_Nullable(this string? str, char value)
{
if (str == null) return false;
return Contains_(str, value);
}
/// <summary>
/// 返回一个值,该值指示指定的子串是否出现在此字符串中。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要搜寻的字符串。</param>
/// <returns>如果 true 参数出现在此字符串中,或者 value 为空字符串 (""),则为 value;否则为 false。</returns>
public static bool Contains_(this string str, string value) => str.Contains(value, StringComparison.Ordinal);
/// <summary>
/// 返回一个值,该值指示指定的子串是否出现在此字符串中。
/// </summary>
/// <param name="str"></param>
/// <param name="value">要搜寻的字符串。</param>
/// <returns>如果 true 参数出现在此字符串中,或者 value 为空字符串 (""),则为 value;否则为 false。</returns>
public static bool Contains_Nullable(this string? str, string value)
{
if (str == null) return false;
return Contains_(str, value);
}
#endregion
#endregion
/// <summary>
/// 将版本号字符串转换为 <see cref="Version"/> 对象,传入的字符串不能为 <see langword="null"/>
/// </summary>
/// <param name="version"></param>
/// <returns></returns>
public static Version? VersionTryParse(string version)
{
var versionChars = GetVersion(version).ToArray();
if (versionChars.Any() && Version.TryParse(new string(versionChars), out var versionObj))
{
return versionObj;
}
static IEnumerable<char> GetVersion(string s)
{
var dianCount = 0;
var findChar = false;
foreach (var item in s)
{
var isDian = item == '.';
if (isDian)
{
if (dianCount++ >= 3)
{
yield break;
}
}
if (isDian || item >= '0' && item <= '9')
{
findChar = true;
yield return item;
}
else if (findChar)
{
yield break;
}
}
}
return null;
}
#region TryParse
/// <summary>
/// 尝试将数字的字符串表示形式转换为它的等效 32 位有符号整数
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static int? TryParseInt32(this string value) => int.TryParse(value, out var temp) ? temp as int? : null;
#endregion
public static string TrimStart(this string s, string trimString)
{
if (trimString.StartsWith(trimString))
{
return s[trimString.Length..];
}
else
{
return s;
}
}
public static string TrimEnd(this string s, string trimString)
{
if (trimString.EndsWith(trimString))
{
return s.Substring(0, s.Length - trimString.Length);
}
else
{
return s;
}
}
#region 数字字母判断
/// <summary>
/// 字符串是否是一个数字(可以零开头 无符号不能+-.)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool IsDigital(this string input) => input?.All(IsDigital) ?? false;
public static bool IsDigital(this char input) => input >= '0' && input <= '9';
/// <summary>
/// 字符串内含有数字
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool HasDigital(this string input) => input?.Any(x => x >= '0' && x <= '9') ?? false;
/// <summary>
/// 字符串内含有小写字母
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool HasLowerLetter(this string input) => input?.Any(x => x >= 'a' && x <= 'z') ?? false;
/// <summary>
/// 字符串内含有大写字母
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool HasUpperLetter(this string input) => input?.Any(x => x >= 'A' && x <= 'Z') ?? false;
/// <summary>
/// 字符串内含有其他字符
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static bool HasOther(this string input) => input?.Any(x => !(x >= 'a' && x <= 'z' || x >= 'A' && x <= 'Z' || x >= '0' && x <= '9')) ?? false;
#endregion
}
}
@@ -0,0 +1,62 @@
// https://github.com/aspnet/AspNetIdentity/blob/master/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
// ReSharper disable once CheckNamespace
namespace System
{
public static class TaskExtensions
{
static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None,
TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static TResult RunSync<TResult>(this Func<Task<TResult>> func)
{
var cultureUi = CultureInfo.CurrentUICulture;
var culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew(() =>
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap().GetAwaiter().GetResult();
}
public static void RunSync(this Func<Task> func)
{
var cultureUi = CultureInfo.CurrentUICulture;
var culture = CultureInfo.CurrentCulture;
_myTaskFactory.StartNew(() =>
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap().GetAwaiter().GetResult();
}
public static TResult RunSync<TResult>(this Func<ValueTask<TResult>> func)
{
var cultureUi = CultureInfo.CurrentUICulture;
var culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew(() =>
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func().AsTask();
}).Unwrap().GetAwaiter().GetResult();
}
public static void RunSync(this Func<ValueTask> func)
{
var cultureUi = CultureInfo.CurrentUICulture;
var culture = CultureInfo.CurrentCulture;
_myTaskFactory.StartNew(() =>
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func().AsTask();
}).Unwrap().GetAwaiter().GetResult();
}
}
}