龙腾猫跃 5 miesięcy temu
rodzic
commit
49c2a9c8ff

+ 4 - 3
Shared/Extensions/EnumerableExtensions.cs

@@ -166,7 +166,8 @@ public static class EnumerableExtensions {
     /// 从 <see cref="ConcurrentDictionary{TKey, TValue}"/> 中移除具有指定键的元素。
     /// 从 <see cref="ConcurrentDictionary{TKey, TValue}"/> 中移除具有指定键的元素。
     /// 返回是否确实移除了元素。
     /// 返回是否确实移除了元素。
     /// </summary>
     /// </summary>
-    public static bool Remove<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key) => dict.TryRemove(key, out _);
+    public static bool Remove<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> dict, TKey key) 
+        => dict.TryRemove(key, out _);
 
 
     /// <summary>
     /// <summary>
     /// 将二维数组转换为字典。
     /// 将二维数组转换为字典。
@@ -182,8 +183,8 @@ public static class EnumerableExtensions {
     /// <summary>
     /// <summary>
     /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。
     /// 尝试从字典中获取某项,如果该项不存在,则返回默认值。
     /// </summary>
     /// </summary>
-    public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default!) =>
-        dict.TryGetValue(key, out var result) ? result : defaultValue;
+    public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default!) 
+        => dict.TryGetValue(key, out var result) ? result : defaultValue;
 
 
     /// <summary>
     /// <summary>
     /// 将值添加到字典的对应项的列表中。
     /// 将值添加到字典的对应项的列表中。

+ 40 - 50
Shared/Extensions/StringExtensions.cs

@@ -6,86 +6,76 @@ public static class StringExtensions {
     #region 区域性 / 大小写 简化
     #region 区域性 / 大小写 简化
 
 
     /// <summary>
     /// <summary>
-    /// 高速的 StartsWith。
+    /// 非区域性的 <see cref="string.StartsWith(string)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool StartsWithF(this string? value, string prefix, bool ignoreCase = false) {
-        if (value is null) return false;
-        return value.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static bool StartsWithF(this string? value, string prefix, bool ignoreCase = false) 
+        => value?.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) ?? false;
     /// <summary>
     /// <summary>
-    /// 高速的 StartsWith。
+    /// 判断字符串是否以 <paramref name="prefix"/> 开头。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool StartsWithF(this string? value, char prefix, bool ignoreCase = false) {
-        if (value is null) return false;
-        return value.StartsWith(prefix.ToString(), ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static bool StartsWithF(this string? value, char prefix, bool ignoreCase = false) 
+        => value?.StartsWith(prefix.ToString(), ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) ?? false;
     /// <summary>
     /// <summary>
-    /// 高速的 EndsWith。
+    /// 非区域性的 <see cref="string.EndsWith(string)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool EndsWithF(this string? value, string suffix, bool ignoreCase = false) {
-        if (value is null) return false;
-        return value.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static bool EndsWithF(this string? value, string suffix, bool ignoreCase = false) 
+        => value?.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) ?? false;
     /// <summary>
     /// <summary>
-    /// 高速的 EndsWith。
+    /// 判断字符串是否以 <paramref name="suffix"/> 结尾。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool EndsWithF(this string? value, char suffix, bool ignoreCase = false) {
-        if (value is null) return false;
-        return value.EndsWith(suffix.ToString(), ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static bool EndsWithF(this string? value, char suffix, bool ignoreCase = false) 
+        => value?.EndsWith(suffix.ToString(), ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) ?? false;
 
 
     /// <summary>
     /// <summary>
-    /// 忽略大小写的 Contains。
+    /// 忽略大小写的 <see cref="string.Contains(string)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static bool ContainsIgnoreCase(this string value, string subString) {
-        return value.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
-    }
+    public static bool ContainsIgnoreCase(this string value, string subString) 
+        => value.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
+
 
 
     /// <summary>
     /// <summary>
-    /// 高速的 IndexOf。
+    /// 非区域性的 <see cref="string.IndexOf(string)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static int IndexOfF(this string value, string subString, bool ignoreCase = false) {
-        return value.IndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static int IndexOfF(this string value, string subString, bool ignoreCase = false) 
+        => value.IndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
     /// <summary>
     /// <summary>
-    /// 高速的 IndexOf。
+    /// 非区域性的 <see cref="string.IndexOf(string, int)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static int IndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) {
-        return value.IndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static int IndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) 
+        => value.IndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
 
 
     /// <summary>
     /// <summary>
-    /// 高速的 LastIndexOf。
+    /// 非区域性的 <see cref="string.LastIndexOf(string)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static int LastIndexOfF(this string value, string subString, bool ignoreCase = false) {
-        return value.LastIndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static int LastIndexOfF(this string value, string subString, bool ignoreCase = false) 
+        => value.LastIndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
     /// <summary>
     /// <summary>
-    /// 高速的 LastIndexOf。
+    /// 非区域性的 <see cref="string.LastIndexOf(string, int)"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static int LastIndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) {
-        return value.LastIndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-    }
+    public static int LastIndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) 
+        => value.LastIndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
 
 
     /// <summary>
     /// <summary>
-    /// ToLowerInvariant 的简略写法。
+    /// <see cref="string.ToLowerInvariant"/> 的简略写法。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string Lower(this string str) => str.ToLowerInvariant();
+    public static string Lower(this string str) 
+        => str.ToLowerInvariant();
     /// <summary>
     /// <summary>
-    /// ToUpperInvariant 的简略写法。
+    /// <see cref="string.ToUpperInvariant"/> 的简略写法。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string Upper(this string str) => str.ToUpperInvariant();
+    public static string Upper(this string str) 
+        => str.ToUpperInvariant();
 
 
     #endregion
     #endregion
 
 
@@ -172,16 +162,15 @@ public static class StringExtensions {
     /// 替换字符串中的内容。
     /// 替换字符串中的内容。
     /// 仅当需要替换时,才调用 <paramref name="newValueGetter"/> 获取结果字符串。
     /// 仅当需要替换时,才调用 <paramref name="newValueGetter"/> 获取结果字符串。
     /// </summary>
     /// </summary>
-    public static string Replace(this string str, string oldValue, Func<string> newValueGetter) =>
-        str.Contains(oldValue) ? str.Replace(oldValue, newValueGetter()) : str;
+    public static string Replace(this string str, string oldValue, Func<string> newValueGetter) 
+        => str.Contains(oldValue) ? str.Replace(oldValue, newValueGetter()) : str;
 
 
     /// <summary>
     /// <summary>
     /// 将字符串中的换行符统一替换为指定字符。
     /// 将字符串中的换行符统一替换为指定字符。
     /// 若指定了 <paramref name="mergeMultiple"/>,会将多个连续换行符仅替换为一个目标内容。
     /// 若指定了 <paramref name="mergeMultiple"/>,会将多个连续换行符仅替换为一个目标内容。
     /// </summary>
     /// </summary>
-    public static string ReplaceLineEndings(this string input, string newValue, bool mergeMultiple = false) {
-        return (mergeMultiple ? regexLineEndingAndMerge : regexLineEnding).Replace(input, newValue.Replace("$", "$$")); // 避免识别成捕获组
-    }
+    public static string ReplaceLineEndings(this string input, string newValue, bool mergeMultiple = false) 
+        => (mergeMultiple ? regexLineEndingAndMerge : regexLineEnding).Replace(input, newValue.Replace("$", "$$")); // 避免识别成捕获组
     private static readonly Regex regexLineEndingAndMerge = new(@"(?:\r\n|[\n\r\f\u0085\u2028\u2029])+", RegexOptions.Compiled);
     private static readonly Regex regexLineEndingAndMerge = new(@"(?:\r\n|[\n\r\f\u0085\u2028\u2029])+", RegexOptions.Compiled);
     private static readonly Regex regexLineEnding = new(@"\r\n|[\n\r\f\u0085\u2028\u2029]", RegexOptions.Compiled);
     private static readonly Regex regexLineEnding = new(@"\r\n|[\n\r\f\u0085\u2028\u2029]", RegexOptions.Compiled);
 
 
@@ -207,6 +196,7 @@ public static class StringExtensions {
     /// <summary>
     /// <summary>
     /// 该字符串中的字符是否均为 ASCII 字符。
     /// 该字符串中的字符是否均为 ASCII 字符。
     /// </summary>
     /// </summary>
-    public static bool IsAsciiOnly(this string input) => input.All(c => c < 128);
+    public static bool IsAsciiOnly(this string input) 
+        => input.All(c => c < 128);
 
 
 }
 }

+ 11 - 14
Shared/General/ConcurrentList.cs

@@ -1,8 +1,7 @@
 namespace MeloongCore;
 namespace MeloongCore;
 
 
 /// <summary>
 /// <summary>
-/// 线程安全的 <see cref="List{T}"/> 实现。
-/// 当调用枚举器时返回一个临时副本,以避免列表在枚举过程中被修改导致异常。
+/// 使用粗粒度锁的线程安全 <see cref="List{T}"/> 实现。
 /// </summary>
 /// </summary>
 public class ConcurrentList<T> : IList<T>, IList, IEnumerable, IEnumerable<T> {
 public class ConcurrentList<T> : IList<T>, IList, IEnumerable, IEnumerable<T> {
 
 
@@ -11,21 +10,19 @@ public class ConcurrentList<T> : IList<T>, IList, IEnumerable, IEnumerable<T> {
 
 
     // 构造函数
     // 构造函数
     public ConcurrentList() { }
     public ConcurrentList() { }
-    public ConcurrentList(IEnumerable<T> data) => _items = new List<T>(data);
+    public ConcurrentList(IEnumerable<T> data) => _items = new(data);
     public static implicit operator ConcurrentList<T>(List<T> data) => new(data);
     public static implicit operator ConcurrentList<T>(List<T> data) => new(data);
-    public static implicit operator List<T>(ConcurrentList<T> data) { lock (data.syncLock) { return new List<T>(data._items); } }
+    public static implicit operator List<T>(ConcurrentList<T> data) { lock (data.syncLock) { return new(data._items); } }
 
 
     // 枚举器
     // 枚举器
-    public IEnumerator<T> GetEnumerator() {
-        lock (syncLock) {
-            return _items.ToList().GetEnumerator();
-        }
-    }
-    IEnumerator IEnumerable.GetEnumerator() {
-        lock (syncLock) {
-            return _items.ToList().GetEnumerator();
-        }
-    }
+    /// <summary>
+    /// 返回此列表的副本。
+    /// </summary>
+    public IEnumerator<T> GetEnumerator() { lock (syncLock) return _items.ToList().GetEnumerator(); }
+    /// <summary>
+    /// 返回此列表的副本。
+    /// </summary>
+    IEnumerator IEnumerable.GetEnumerator() { lock (syncLock) return _items.ToList().GetEnumerator(); }
 
 
     // 成员
     // 成员
     public int Count { get { lock (syncLock) { return _items.Count; } } }
     public int Count { get { lock (syncLock) { return _items.Count; } } }

+ 43 - 31
Shared/General/Logger.cs

@@ -6,7 +6,7 @@ namespace MeloongCore;
 /// <summary>
 /// <summary>
 /// 日志等级。
 /// 日志等级。
 /// </summary>
 /// </summary>
-public enum LogLevels {
+public enum LogLevel {
     /// <summary>
     /// <summary>
     /// 追踪。
     /// 追踪。
     /// </summary>
     /// </summary>
@@ -28,7 +28,7 @@ public enum LogLevels {
 /// <summary>
 /// <summary>
 /// 输出日志时执行的错误汇报行为。
 /// 输出日志时执行的错误汇报行为。
 /// </summary>
 /// </summary>
-public enum LogBehaviors {
+public enum LogBehavior {
     /// <summary>
     /// <summary>
     /// 无提示。
     /// 无提示。
     /// </summary>
     /// </summary>
@@ -59,41 +59,53 @@ public static class Logger {
     public static BaseLogger Instance { get; set; } = new();
     public static BaseLogger Instance { get; set; } = new();
 
 
     // 转发给实例的方法包装
     // 转发给实例的方法包装
-    public static void Log(string message, LogLevels level = LogLevels.Info, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") 
+    public static void Log(string message, LogLevel level = LogLevel.Info, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
         => Instance.Log(message, level, behavior, filePath);
         => Instance.Log(message, level, behavior, filePath);
-    public static void Trace(string message, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(message, LogLevels.Trace, behavior, filePath);
-    public static void Info(string message, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(message, LogLevels.Info, behavior, filePath);
-    public static void Warning(string message, LogBehaviors behavior = LogBehaviors.ToastIfDebug, [CallerFilePath] string filePath = "") => Log(message, LogLevels.Warning, behavior, filePath);
-    public static void Error(string message, LogBehaviors behavior = LogBehaviors.AlertThenFeedback, [CallerFilePath] string filePath = "") => Log(message, LogLevels.Error, behavior, filePath);
-
-    public static void Log(Func<string> messageGetter, LogLevels level = LogLevels.Info, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") {
+    public static void Trace(string message, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(message, LogLevel.Trace, behavior, filePath);
+    public static void Info(string message, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(message, LogLevel.Info, behavior, filePath);
+    public static void Warning(string message, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "") 
+        => Log(message, LogLevel.Warning, behavior, filePath);
+    public static void Error(string message, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "") 
+        => Log(message, LogLevel.Error, behavior, filePath);
+
+    public static void Log(Func<string> messageGetter, LogLevel level = LogLevel.Info, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") {
         if (Instance.MinLevel <= level) Instance.Log(messageGetter(), level, behavior, filePath); }
         if (Instance.MinLevel <= level) Instance.Log(messageGetter(), level, behavior, filePath); }
-    public static void Trace(Func<string> messageGetter, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(messageGetter, LogLevels.Trace, behavior, filePath);
-    public static void Info(Func<string> messageGetter, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(messageGetter, LogLevels.Info, behavior, filePath);
-    public static void Warning(Func<string> messageGetter, LogBehaviors behavior = LogBehaviors.ToastIfDebug, [CallerFilePath] string filePath = "") => Log(messageGetter, LogLevels.Warning, behavior, filePath);
-    public static void Error(Func<string> messageGetter, LogBehaviors behavior = LogBehaviors.AlertThenFeedback, [CallerFilePath] string filePath = "") => Log(messageGetter, LogLevels.Error, behavior, filePath);
-
-    public static void Log(Exception ex, string? message = null, LogLevels level = LogLevels.Warning, LogBehaviors behavior = LogBehaviors.ToastIfDebug, [CallerFilePath] string filePath = "") 
+    public static void Trace(Func<string> messageGetter, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(messageGetter, LogLevel.Trace, behavior, filePath);
+    public static void Info(Func<string> messageGetter, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(messageGetter, LogLevel.Info, behavior, filePath);
+    public static void Warning(Func<string> messageGetter, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "") 
+        => Log(messageGetter, LogLevel.Warning, behavior, filePath);
+    public static void Error(Func<string> messageGetter, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "") 
+        => Log(messageGetter, LogLevel.Error, behavior, filePath);
+
+    public static void Log(Exception ex, string? message = null, LogLevel level = LogLevel.Warning, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "") 
         => Instance.Log(ex, message, level, behavior, filePath);
         => Instance.Log(ex, message, level, behavior, filePath);
-    public static void Trace(Exception ex, string? message = null, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(ex, message, LogLevels.Trace, behavior, filePath);
-    public static void Info(Exception ex, string? message = null, LogBehaviors behavior = LogBehaviors.None, [CallerFilePath] string filePath = "") => Log(ex, message, LogLevels.Info, behavior, filePath);
-    public static void Warning(Exception ex, string? message = null, LogBehaviors behavior = LogBehaviors.ToastIfDebug, [CallerFilePath] string filePath = "") => Log(ex, message, LogLevels.Warning, behavior, filePath);
-    public static void Error(Exception ex, string? message = null, LogBehaviors behavior = LogBehaviors.AlertThenFeedback, [CallerFilePath] string filePath = "") => Log(ex, message, LogLevels.Error, behavior, filePath);
+    public static void Trace(Exception ex, string? message = null, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(ex, message, LogLevel.Trace, behavior, filePath);
+    public static void Info(Exception ex, string? message = null, LogBehavior behavior = LogBehavior.None, [CallerFilePath] string filePath = "") 
+        => Log(ex, message, LogLevel.Info, behavior, filePath);
+    public static void Warning(Exception ex, string? message = null, LogBehavior behavior = LogBehavior.ToastIfDebug, [CallerFilePath] string filePath = "") 
+        => Log(ex, message, LogLevel.Warning, behavior, filePath);
+    public static void Error(Exception ex, string? message = null, LogBehavior behavior = LogBehavior.AlertThenFeedback, [CallerFilePath] string filePath = "") 
+        => Log(ex, message, LogLevel.Error, behavior, filePath);
 }
 }
 
 
 /// <summary>
 /// <summary>
 /// 最基础的日志实现。
 /// 最基础的日志实现。
-/// 仅将日志输出到 <see cref="Debug"/>,不实现 <see cref="LogBehaviors"/>。
+/// 仅将日志输出到 <see cref="Debug"/>,不实现 <see cref="LogBehavior"/>。
 /// </summary>
 /// </summary>
 public class BaseLogger {
 public class BaseLogger {
 
 
     /// <summary>
     /// <summary>
     /// 最低日志输出等级,低于此等级的日志将被忽略。
     /// 最低日志输出等级,低于此等级的日志将被忽略。
     /// </summary>
     /// </summary>
-    public LogLevels MinLevel { get; set; } = LogLevels.Trace;
+    public LogLevel MinLevel { get; set; } = LogLevel.Trace;
 
 
     // 核心方法
     // 核心方法
-    public virtual void Log(string message, LogLevels level, LogBehaviors behavior, string filePath) {
+    public virtual void Log(string message, LogLevel level, LogBehavior behavior, string filePath) {
         if (MinLevel > level) return;
         if (MinLevel > level) return;
         try {
         try {
             var formattedMessage = Format(message, level, filePath, null);
             var formattedMessage = Format(message, level, filePath, null);
@@ -101,7 +113,7 @@ public class BaseLogger {
             HandleBehavior(message, formattedMessage, behavior, null);
             HandleBehavior(message, formattedMessage, behavior, null);
         } catch {}
         } catch {}
     }
     }
-    public virtual void Log(Exception ex, string? message, LogLevels level, LogBehaviors behavior, string filePath) {
+    public virtual void Log(Exception ex, string? message, LogLevel level, LogBehavior behavior, string filePath) {
         if (MinLevel > level) return;
         if (MinLevel > level) return;
         if (ex is ThreadInterruptedException) return;
         if (ex is ThreadInterruptedException) return;
         try {
         try {
@@ -115,7 +127,7 @@ public class BaseLogger {
     /// <summary>
     /// <summary>
     /// 格式化日志文本。
     /// 格式化日志文本。
     /// </summary>
     /// </summary>
-    protected virtual string Format(string text, LogLevels level, string filePath, Exception? ex) {
+    protected virtual string Format(string text, LogLevel level, string filePath, Exception? ex) {
         string prefix = $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {(Thread.CurrentThread.Name is null ? "" : $"<{Thread.CurrentThread.Name}> ")}[{Path.GetFileName(filePath).BeforeFirst(".")}] ";
         string prefix = $"{DateTime.Now:HH':'mm':'ss'.'fff} {level.ToString().First()} {(Thread.CurrentThread.Name is null ? "" : $"<{Thread.CurrentThread.Name}> ")}[{Path.GetFileName(filePath).BeforeFirst(".")}] ";
         return text
         return text
             .ReplaceLineEndings("\n", mergeMultiple: true).Split(['\n'], StringSplitOptions.RemoveEmptyEntries)
             .ReplaceLineEndings("\n", mergeMultiple: true).Split(['\n'], StringSplitOptions.RemoveEmptyEntries)
@@ -126,26 +138,26 @@ public class BaseLogger {
     /// <summary>
     /// <summary>
     /// 输出格式化后的日志文本。
     /// 输出格式化后的日志文本。
     /// </summary>
     /// </summary>
-    protected virtual void Output(string formattedMessage, LogLevels level) {
+    protected virtual void Output(string formattedMessage, LogLevel level) {
         Debug.WriteLine(formattedMessage);
         Debug.WriteLine(formattedMessage);
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// 在调用 Log 方法的线程执行 <see cref="LogBehaviors"/>。
+    /// 在调用 Log 方法的线程执行 <see cref="LogBehavior"/>。
     /// </summary>
     /// </summary>
-    protected virtual void HandleBehavior(string? rawMessage, string formattedMessage, LogBehaviors behavior, Exception? ex) {
+    protected virtual void HandleBehavior(string? rawMessage, string formattedMessage, LogBehavior behavior, Exception? ex) {
     }
     }
 
 
 }
 }
 
 
 /// <summary>
 /// <summary>
 /// 将日志输出到 <see cref="Debug"/> 并写入指定的文件夹,最多保留 5 个文件。
 /// 将日志输出到 <see cref="Debug"/> 并写入指定的文件夹,最多保留 5 个文件。
-/// 不实现 <see cref="LogBehaviors"/>。
+/// 不实现 <see cref="LogBehavior"/>。
 /// </summary>
 /// </summary>
 public class FileLogger : BaseLogger, IDisposable {
 public class FileLogger : BaseLogger, IDisposable {
 
 
     /// <inheritdoc/>
     /// <inheritdoc/>
-    protected override void Output(string formattedText, LogLevels level) {
+    protected override void Output(string formattedText, LogLevel level) {
         base.Output(formattedText, level);
         base.Output(formattedText, level);
         if (!writerAvaliable && queue.Count >= 100) return; // 在 writer 就绪前,最多缓存 100 条日志
         if (!writerAvaliable && queue.Count >= 100) return; // 在 writer 就绪前,最多缓存 100 条日志
         queue.Enqueue(formattedText);
         queue.Enqueue(formattedText);
@@ -187,7 +199,7 @@ public class FileLogger : BaseLogger, IDisposable {
                     FileUtils.Delete(olderFile);
                     FileUtils.Delete(olderFile);
                 }
                 }
             } catch (IOException ex) {
             } catch (IOException ex) {
-                Logger.Warning(ex, "可能同时开启了多个程序,这或许会导致未知问题", LogBehaviors.Toast);
+                Logger.Warning(ex, "可能同时开启了多个程序,这或许会导致未知问题", LogBehavior.Toast);
             } catch (Exception ex) {
             } catch (Exception ex) {
                 Logger.Warning(ex, "整理日志文件失败");
                 Logger.Warning(ex, "整理日志文件失败");
             }
             }
@@ -201,7 +213,7 @@ public class FileLogger : BaseLogger, IDisposable {
                     Flush();
                     Flush();
                 }
                 }
             } catch (Exception ex) {
             } catch (Exception ex) {
-                Logger.Warning(ex, "写入日志文件失败", LogBehaviors.Toast);
+                Logger.Warning(ex, "写入日志文件失败", LogBehavior.Toast);
                 writerAvaliable = false;
                 writerAvaliable = false;
             }
             }
         }) { Name = nameof(FileLogger), Priority = ThreadPriority.Lowest, IsBackground = true };
         }) { Name = nameof(FileLogger), Priority = ThreadPriority.Lowest, IsBackground = true };

+ 1 - 1
Shared/General/MsDelta.cs

@@ -39,7 +39,7 @@ public static class MsDelta {
             throw new Win32Exception();
             throw new Win32Exception();
     }
     }
 
 
-
+    // API
     [StructLayout(LayoutKind.Sequential)]
     [StructLayout(LayoutKind.Sequential)]
     private struct DeltaInput {
     private struct DeltaInput {
         public IntPtr Start;
         public IntPtr Start;

+ 4 - 6
Shared/Utils/DirectoryUtils.cs

@@ -16,16 +16,14 @@ public static class DirectoryUtils {
     /// <summary>
     /// <summary>
     /// 判断文件夹是否存在。
     /// 判断文件夹是否存在。
     /// </summary>
     /// </summary>
-    public static bool Exists(string path) {
-        return Directory.Exists(PathUtils.WithLongPath(path));
-    }
+    public static bool Exists(string path) 
+        => Directory.Exists(PathUtils.WithLongPath(path));
 
 
     /// <summary>
     /// <summary>
     /// 创建 <see cref="DirectoryInfo"/> 对象。
     /// 创建 <see cref="DirectoryInfo"/> 对象。
     /// </summary>
     /// </summary>
-    public static DirectoryInfo GetInfo(string path) {
-        return new(PathUtils.WithLongPath(path));
-    }
+    public static DirectoryInfo GetInfo(string path) 
+        => new(PathUtils.WithLongPath(path));
 
 
     /// <summary>
     /// <summary>
     /// 返回指定路径下的所有文件,不以 \\?\ 开头。
     /// 返回指定路径下的所有文件,不以 \\?\ 开头。

+ 32 - 16
Shared/Utils/EscapeUtils.cs

@@ -30,51 +30,67 @@ public static class EscapeUtils {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// 正则表达式转义。等同于 Regex.Escape。
+    /// 正则表达式转义。
+    /// 等同于 <see cref="Regex.Escape"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? RegexEscape(string? value) => Regex.Escape(value);
+    public static string? RegexEscape(string? value) 
+        => Regex.Escape(value);
 
 
     /// <summary>
     /// <summary>
-    /// 正则表达式去转义。等同于 Regex.Unescape。
+    /// 正则表达式去转义。
+    /// 等同于 <see cref="Regex.Unescape"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? RegexUnescape(string? value) => Regex.Unescape(value);
+    public static string? RegexUnescape(string? value) 
+        => Regex.Unescape(value);
 
 
     /// <summary>
     /// <summary>
-    /// URL 转义。等同于 Uri.EscapeDataString。
+    /// URL 转义。
+    /// 等同于 <see cref="Uri.EscapeDataString"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? UrlEscape(string? value) => Uri.EscapeDataString(value);
+    public static string? UrlEscape(string? value) 
+        => Uri.EscapeDataString(value);
 
 
     /// <summary>
     /// <summary>
-    /// URL 去转义。等同于 Uri.UnescapeDataString。
+    /// URL 去转义。
+    /// 等同于 <see cref="Uri.UnescapeDataString"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? UrlUnescape(string? value) => Uri.UnescapeDataString(value);
+    public static string? UrlUnescape(string? value) 
+        => Uri.UnescapeDataString(value);
 
 
     /// <summary>
     /// <summary>
-    /// 表单转义。等同于 WebUtility.UrlEncode。
+    /// 表单转义。
+    /// 等同于 <see cref="WebUtility.UrlEncode"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? FormUrlEscape(string? value) => WebUtility.UrlEncode(value);
+    public static string? FormUrlEscape(string? value) 
+        => WebUtility.UrlEncode(value);
 
 
     /// <summary>
     /// <summary>
-    /// 表单去转义。等同于 WebUtility.UrlDecode。
+    /// 表单去转义。
+    /// 等同于 <see cref="WebUtility.UrlDecode"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? FormUrlUnescape(string? value) => WebUtility.UrlDecode(value);
+    public static string? FormUrlUnescape(string? value) 
+        => WebUtility.UrlDecode(value);
 
 
     /// <summary>
     /// <summary>
-    /// HTML 转义。等同于 WebUtility.HtmlEncode。
+    /// HTML 转义。
+    /// 等同于 <see cref="WebUtility.HtmlEncode"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? HtmlEscape(string? value) => WebUtility.HtmlEncode(value);
+    public static string? HtmlEscape(string? value) 
+        => WebUtility.HtmlEncode(value);
 
 
     /// <summary>
     /// <summary>
-    /// HTML 去转义。等同于 WebUtility.HtmlDecode。
+    /// HTML 去转义。
+    /// 等同于 <see cref="WebUtility.HtmlDecode"/>。
     /// </summary>
     /// </summary>
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
     [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public static string? HtmlUnescape(string? value) => WebUtility.HtmlDecode(value);
+    public static string? HtmlUnescape(string? value) 
+        => WebUtility.HtmlDecode(value);
 
 
 }
 }

+ 11 - 16
Shared/Utils/FileUtils.cs

@@ -9,17 +9,15 @@ public static class FileUtils {
     /// 写入文件。
     /// 写入文件。
     /// 如果文件或文件夹不存在,则会自动创建。若已存在,则会覆盖原文件。
     /// 如果文件或文件夹不存在,则会自动创建。若已存在,则会覆盖原文件。
     /// </summary>
     /// </summary>
-    public static void Write(string filePath, string text, Encoding? encoding = null) {
-        Write(filePath, (encoding ?? new UTF8Encoding()).GetBytes(text));
-    }
+    public static void Write(string filePath, string text, Encoding? encoding = null) 
+        => Write(filePath, (encoding ?? new UTF8Encoding()).GetBytes(text));
 
 
     /// <summary>
     /// <summary>
     /// 写入文件。
     /// 写入文件。
     /// 如果文件或文件夹不存在,则会自动创建。若已存在,则会覆盖原文件。
     /// 如果文件或文件夹不存在,则会自动创建。若已存在,则会覆盖原文件。
     /// </summary>
     /// </summary>
-    public static void Write(string filePath, IEnumerable<byte> content) {
-        Write(filePath, [..content]);
-    }
+    public static void Write(string filePath, IEnumerable<byte> content) 
+        => Write(filePath, [.. content]);
 
 
     /// <summary>
     /// <summary>
     /// 写入文件。
     /// 写入文件。
@@ -94,7 +92,7 @@ public static class FileUtils {
             internalEx?.Throw();
             internalEx?.Throw();
         }
         }
     }
     }
-    // 用于删除到回收站的接口
+    // API
     [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
     [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
     static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
     static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
     [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
@@ -132,9 +130,8 @@ public static class FileUtils {
     /// <summary>
     /// <summary>
     /// 打开该文件的只读 <see cref="FileStream"/>。
     /// 打开该文件的只读 <see cref="FileStream"/>。
     /// </summary>
     /// </summary>
-    public static FileStream ReadAsStream(string filePath) {
-        return new(PathUtils.WithLongPath(filePath), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
-    }
+    public static FileStream ReadAsStream(string filePath) 
+        => new(PathUtils.WithLongPath(filePath), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
 
 
     /// <summary>
     /// <summary>
     /// 在指定路径创建文件,并打开 <see cref="FileStream"/>。
     /// 在指定路径创建文件,并打开 <see cref="FileStream"/>。
@@ -260,16 +257,14 @@ public static class FileUtils {
     /// <summary>
     /// <summary>
     /// 确定指定的文件是否存在。
     /// 确定指定的文件是否存在。
     /// </summary>
     /// </summary>
-    public static bool Exists(string filePath) {
-        return File.Exists(PathUtils.WithLongPath(filePath));
-    }
+    public static bool Exists(string filePath) 
+        => File.Exists(PathUtils.WithLongPath(filePath));
 
 
     /// <summary>
     /// <summary>
     /// 创建 <see cref="FileInfo"/> 对象。
     /// 创建 <see cref="FileInfo"/> 对象。
     /// </summary>
     /// </summary>
-    public static FileInfo GetInfo(string path) {
-        return new(PathUtils.WithLongPath(path));
-    }
+    public static FileInfo GetInfo(string path) 
+        => new(PathUtils.WithLongPath(path));
 
 
     /// <summary>
     /// <summary>
     /// 复制文件。
     /// 复制文件。

+ 0 - 4
Shared/Utils/HttpUtils.cs

@@ -13,7 +13,3 @@ public class HttpRequestCodeException(string message, HttpStatusCode statusCode,
     /// </summary>
     /// </summary>
     public string? Response { get; set; } = response;
     public string? Response { get; set; } = response;
 }
 }
-
-public static class HttpUtils {
-
-}

+ 9 - 5
Shared/Utils/MathUtils.cs

@@ -30,17 +30,21 @@ public static class MathUtils {
     /// 转换为 2 到 86 进制的字符串。
     /// 转换为 2 到 86 进制的字符串。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// </summary>
     /// </summary>
-    public static string ConvertRadix(this long input, int toRadix) => ConvertRadix((BigInteger) input, toRadix);
+    public static string ConvertRadix(this long input, int toRadix) 
+        => ConvertRadix((BigInteger) input, toRadix);
     /// <summary>
     /// <summary>
     /// 转换为 2 到 86 进制的字符串。
     /// 转换为 2 到 86 进制的字符串。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// </summary>
     /// </summary>
-    public static string ConvertRadix(this int input, int toRadix) => ConvertRadix((BigInteger) input, toRadix);
+    public static string ConvertRadix(this int input, int toRadix) 
+        => ConvertRadix((BigInteger) input, toRadix);
     /// <summary>
     /// <summary>
     /// 转换为 2 到 86 进制的字符串。
     /// 转换为 2 到 86 进制的字符串。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// 进制参考:含大写字母 36,含大小写字母 62,含大小写字母和特殊符号 86。
     /// </summary>
     /// </summary>
-    public static string ConvertRadix(this byte input, int toRadix) => ConvertRadix((BigInteger) input, toRadix);
+    public static string ConvertRadix(this byte input, int toRadix) 
+        => ConvertRadix((BigInteger) input, toRadix);
+
     private static string ConvertRadix(this BigInteger input, int toRadix) {
     private static string ConvertRadix(this BigInteger input, int toRadix) {
         const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+=!?@#$%^&*()[]{}<>;:',";
         const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+=!?@#$%^&*()[]{}<>;:',";
         if (toRadix < 2 || toRadix > digits.Length) throw new ArgumentOutOfRangeException(nameof(toRadix), $"{nameof(toRadix)} must be between 2 and 86.");
         if (toRadix < 2 || toRadix > digits.Length) throw new ArgumentOutOfRangeException(nameof(toRadix), $"{nameof(toRadix)} must be between 2 and 86.");
@@ -76,8 +80,8 @@ public static class MathUtils {
     /// 在一个范围中进行线性插值。
     /// 在一个范围中进行线性插值。
     /// 返回值将被舍入到小数点后 7 位,以解决浮点数误差问题。
     /// 返回值将被舍入到小数点后 7 位,以解决浮点数误差问题。
     /// </summary>
     /// </summary>
-    public static double Lerp(double start, double end, double percentage) => 
-        Math.Round(start + (end - start) * percentage, 7);
+    public static double Lerp(double start, double end, double percentage)
+        => Math.Round(start + (end - start) * percentage, 7);
 
 
     /// <summary>
     /// <summary>
     /// 计算二阶贝塞尔曲线。
     /// 计算二阶贝塞尔曲线。

+ 8 - 10
Shared/Utils/PathUtils.cs

@@ -6,16 +6,14 @@ public static class PathUtils {
     /// <summary>
     /// <summary>
     /// 确保路径的结尾包含文件夹分隔符。
     /// 确保路径的结尾包含文件夹分隔符。
     /// </summary>
     /// </summary>
-    public static string WithSeparator(string folder) {
-        return folder.EndsWithF(Path.DirectorySeparatorChar) ? folder : folder + Path.DirectorySeparatorChar;
-    }
+    public static string WithSeparator(string folder) 
+        => folder.EndsWithF(Path.DirectorySeparatorChar) ? folder : folder + Path.DirectorySeparatorChar;
 
 
     /// <summary>
     /// <summary>
     /// 确保路径的结尾不包含文件夹分隔符。
     /// 确保路径的结尾不包含文件夹分隔符。
     /// </summary>
     /// </summary>
-    public static string WithoutSeparator(string folder) {
-        return folder.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
-    }
+    public static string WithoutSeparator(string folder) 
+        => folder.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
 
 
     #endregion
     #endregion
 
 
@@ -59,7 +57,7 @@ public static class PathUtils {
     private static extern int GetShortPathNameW(string lpszLongPath, [Out] char[] buffer, int cchBuffer);
     private static extern int GetShortPathNameW(string lpszLongPath, [Out] char[] buffer, int cchBuffer);
 
 
     /// <summary>
     /// <summary>
-    /// 将完整路径转换为以 \\?\ 开头的标准长路径格式。
+    /// 将完整路径转换为以 <c>\\?\</c> 开头的标准长路径格式。
     /// 这会去除路径末尾的分隔符,且将 / 替换为 \。
     /// 这会去除路径末尾的分隔符,且将 / 替换为 \。
     /// </summary>
     /// </summary>
     public static string WithLongPath(string path) {
     public static string WithLongPath(string path) {
@@ -74,10 +72,10 @@ public static class PathUtils {
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// 去除路径开头的 \\?\。
+    /// 去除路径开头的 <c>\\?\</c>。
     /// </summary>
     /// </summary>
-    public static string WithoutLongPath(string path) =>
-        path.AfterLast(@"\\?\");
+    public static string WithoutLongPath(string path) 
+        => path.AfterLast(@"\\?\");
 
 
     #endregion
     #endregion