You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
35 KiB

4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
4 years ago
2 years ago
4 years ago
4 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
2 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
2 years ago
4 years ago
2 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
  1. using Apewer;
  2. using Apewer.Internals;
  3. using Apewer.Source;
  4. using Apewer.Web;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Data;
  9. using System.Diagnostics;
  10. using System.IO;
  11. using System.Reflection;
  12. using System.Text;
  13. using System.Collections.Specialized;
  14. #if !NET20
  15. using System.Dynamic;
  16. #endif
  17. /// <summary>扩展方法。</summary>
  18. public static class Extensions
  19. {
  20. /// <summary>是 NULL 值。</summary>
  21. public static bool IsNull(this object @this) => @this == null || @this.Equals(DBNull.Value);
  22. /// <summary>不是 NULL 值。</summary>
  23. public static bool NotNull(this object @this) => @this != null && !@this.Equals(DBNull.Value);
  24. /// <summary>是默认值。</summary>
  25. public static bool IsDefault(this object @this) => RuntimeUtility.IsDefault(@this);
  26. #region Class Utility
  27. /// <summary>调用 Get 方法。</summary>
  28. public static object Get(this PropertyInfo @this, object instance) => RuntimeUtility.InvokeGet<object>(instance, @this);
  29. /// <summary>调用 Set 方法。</summary>
  30. public static void Set(this PropertyInfo @this, object instance, object value) => RuntimeUtility.InvokeSet<object>(instance, @this, value);
  31. /// <summary>调用 Get 方法。</summary>
  32. public static T Get<T>(this PropertyInfo @this, object instance) => RuntimeUtility.InvokeGet<T>(instance, @this);
  33. /// <summary>调用 Set 方法。</summary>
  34. public static void Set<T>(this PropertyInfo @this, object instance, T value) => RuntimeUtility.InvokeSet<T>(instance, @this, value);
  35. /// <summary>调用方法。</summary>
  36. /// <exception cref="ArgumentException"></exception>
  37. /// <exception cref="InvalidOperationException"></exception>
  38. /// <exception cref="MethodAccessException"></exception>
  39. /// <exception cref="NotSupportedException"></exception>
  40. /// <exception cref="TargetException"></exception>
  41. /// <exception cref="TargetInvocationException"></exception>
  42. /// <exception cref="TargetParameterCountException"></exception>
  43. public static object Invoke(this MethodInfo @this, object instace, params object[] parameters) => RuntimeUtility.InvokeMethod(instace, @this, parameters);
  44. /// <summary>判断静态属性。</summary>
  45. public static bool IsStatic(this PropertyInfo @this) => RuntimeUtility.IsStatic(@this);
  46. /// <summary>以安全的方式获取消息内容,对无效的 Exception 返回 NULL 值。</summary>
  47. public static string Message(this Exception ex) => RuntimeUtility.Message(ex);
  48. #if NET20
  49. /// <summary>为指定对象设置属性值。</summary>
  50. /// <param name="property">属性。</param>
  51. /// <param name="obj">要设置属性的对象。</param>
  52. /// <param name="value">属性值。</param>
  53. /// <exception cref="ArgumentNullException"></exception>
  54. public static void SetValue(this PropertyInfo property, object obj, object value)
  55. {
  56. if (property == null) throw new ArgumentNullException(nameof(property));
  57. property.SetValue(obj, value, null);
  58. }
  59. #endif
  60. #endregion
  61. #region Dynamic
  62. #if !NET20
  63. /// <summary>转换 <see cref="ObjectSet{T}"/> 到 <see cref="ExpandoObject"/> 对象。</summary>
  64. public static ExpandoObject Expando<T>(this ObjectSet<T> os) => ObjectSet<T>.Expando(os);
  65. /// <summary>转换 <see cref="ObjectSet{T}"/> 数组到 <see cref="ExpandoObject"/> 数组。</summary>
  66. public static ExpandoObject[] Expando<T>(this ObjectSet<T>[] oss) => ObjectSet<T>.Expando(oss);
  67. /// <summary>设置 <see cref="ObjectSet{T}"/> 的 Always 属性,对动态属性的访问始终返回 TRUE 值。</summary>
  68. public static void SetAlways<T>(this ObjectSet<T> os, bool always) => os._always = always;
  69. #endif
  70. #endregion
  71. #region Number
  72. /// <summary>判断此值为零。</summary>
  73. public static bool IsZero(this decimal @this) => @this.Equals(0M);
  74. /// <summary>判断此值为零。</summary>
  75. public static bool IsZero(this double @this) => @this.Equals(0D);
  76. /// <summary>判断此值为零。</summary>
  77. public static bool IsZero(this float @this) => @this.Equals(0F);
  78. /// <summary>判断此值非零。</summary>
  79. public static bool NotZero(this decimal @this) => !@this.Equals(0M);
  80. /// <summary>判断此值非零。</summary>
  81. public static bool NotZero(this double @this) => !@this.Equals(0D);
  82. /// <summary>判断此值非零。</summary>
  83. public static bool NotZero(this float @this) => !@this.Equals(0F);
  84. /// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
  85. public static T Restrict<T>(this T @this, T min, T max) where T : IComparable => NumberUtility.Restrict(@this, min, max);
  86. #endregion
  87. #region String、StringBuilder
  88. /// <summary>转换文本为驼峰形式。</summary>
  89. public static string Camel(this string @this) => TextUtility.Camel(@this);
  90. /// <summary>转换为 Boolean 值。</summary>
  91. public static bool Boolean(this string @this) => NumberUtility.Boolean(@this);
  92. /// <summary>转换为 Byte 值。</summary>
  93. public static byte Byte(this string @this) => NumberUtility.Byte(@this);
  94. /// <summary>转换为 Int32 值。</summary>
  95. public static int Int32(this string @this) => NumberUtility.Int32(@this);
  96. /// <summary>转换为 Int64 值。</summary>
  97. public static long Int64(this string @this) => NumberUtility.Int64(@this);
  98. /// <summary>转换为 Decimal 值。</summary>
  99. public static decimal Decimal(this string @this) => NumberUtility.Decimal(@this);
  100. /// <summary>转换为单精度浮点值。</summary>
  101. public static float Float(this string @this) => NumberUtility.Float(@this);
  102. /// <summary>转换为双精度浮点值。</summary>
  103. public static double Double(this string @this) => NumberUtility.Double(@this);
  104. /// <summary>将文本转换为字节数组,默认使用 UTF-8。</summary>
  105. public static byte[] Bytes(this string @this, Encoding encoding = null) => TextUtility.Bytes(@this, encoding);
  106. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  107. public static bool IsEmpty(this string @this) => TextUtility.IsEmpty(@this);
  108. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  109. public static bool NotEmpty(this string @this) => TextUtility.NotEmpty(@this);
  110. /// <summary>验证字符串为 NULL、为空或无实际内容。</summary>
  111. public static bool IsBlank(this string @this) => TextUtility.IsBlank(@this);
  112. /// <summary>验证字符串含有实际内容。</summary>
  113. public static bool NotBlank(this string @this) => TextUtility.NotBlank(@this);
  114. /// <summary>用指定的分隔符拆分文本。</summary>
  115. public static string[] Split(this string @this, string separator) => TextUtility.Split(@this, separator);
  116. /// <summary>使用多个分隔符切分字符串,得到多个子字符串。</summary>
  117. public static string[] Split(this string @this, params char[] separators) => TextUtility.Split(@this, separators);
  118. /// <summary>返回此字符串的安全键副本。</summary>
  119. public static string SafeKey(this string @this, int maxLength = 255) => TextUtility.SafeKey(@this, maxLength);
  120. /// <summary>移除字符串前后的空字符。</summary>
  121. /// <remarks>trimBlank:移除空格、全角空格、换行符、回车符、制表符和换页符。</remarks>
  122. public static string Trim(this string @this, bool trimBlank = false) => TextUtility.Trim(@this, trimBlank);
  123. /// <summary>移除字符串前后的空字符。</summary>
  124. /// <remarks>trimBlank:移除空格、全角空格、换行符、回车符、制表符和换页符。</remarks>
  125. public static string ToTrim(this string @this, bool trimBlank = false) => TextUtility.Trim(@this, trimBlank);
  126. /// <summary>返回此字符串转换为小写形式的副本。</summary>
  127. public static string Lower(this string @this) => TextUtility.Lower(@this);
  128. /// <summary>返回此字符串转换为大写形式的副本。</summary>
  129. public static string Upper(this string @this) => TextUtility.Upper(@this);
  130. /// <summary>追加字符串。</summary>
  131. public static string Append(this string @this, params object[] text) => TextUtility.Merge(@this, TextUtility.Merge(text));
  132. /// <summary>追加文本。</summary>
  133. public static void Append(this StringBuilder @this, params object[] text) => TextUtility.Append(@this, text);
  134. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  135. public static string AntiInject(this string @this, int length = -1, string blacklist = null) => TextUtility.AntiInject(@this, length, blacklist);
  136. /// <summary>将 Base64 字符串转换为字节数组。</summary>
  137. public static byte[] Base64(this string @this) => BytesUtility.FromBase64(@this);
  138. /// <summary>对 URL 编码。</summary>
  139. public static string EncodeUrl(this string @this) => UrlEncoding.Encode(@this);
  140. /// <summary>对 URL 解码。</summary>
  141. public static string DecodeUrl(this string @this) => UrlEncoding.Decode(@this);
  142. /// <summary>获取指定长度的字符串片段,可指定 trim 参数对片段再次修剪。</summary>
  143. public static string Left(this string text, int maxLength, bool trim = false) => TextUtility.Left(text, maxLength, trim);
  144. /// <summary>获取指定长度的字符串片段,可指定 trim 参数对片段再次修剪。</summary>
  145. public static string Right(this string text, int maxLength, bool trim = false) => TextUtility.Right(text, maxLength, trim);
  146. /// <summary>剪取文本内容,若指定头部为空则从原文本首部起,若指定尾部为空则至原文本末尾。</summary>
  147. /// <returns>剪取后的内容,不包含 head 和 foot。</returns>
  148. public static string Cut(this string text, string head = null, string foot = null) => TextUtility.Cut(text, head, foot);
  149. /// <summary>约束字符串中的字符,只包含指定的字符。</summary>
  150. public static string Restrict(this string text, char[] chars) => TextUtility.Restrict(text, chars);
  151. /// <summary>约束字符串中的字符,只包含指定的字符。</summary>
  152. public static string Restrict(this string text, string chars) => TextUtility.Restrict(text, chars);
  153. /// <summary>连接字符串。</summary>
  154. public static string Join(this IEnumerable<string> strings, string separator) => TextUtility.Join(separator, strings);
  155. #endregion
  156. #region Byte[]
  157. /// <summary>将字节数组格式化为十六进制字符串,默认为大写。<para>例:D41D8CD98F00B204E9800998ECF8427E</para></summary>
  158. public static string X2(this byte[] @this, bool upperCase = true) => BytesUtility.ToX2(upperCase, @this);
  159. /// <summary>克隆字节数组。当源为 NULL 时,将获取零元素字节数组。</summary>
  160. public static byte[] Clone(this byte[] @this) => BytesUtility.Clone(@this);
  161. /// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
  162. public static bool Starts(this byte[] @this, params byte[] head) => BytesUtility.StartsWith(@this, head);
  163. /// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
  164. public static bool Ends(this byte[] @this, params byte[] head) => BytesUtility.EndsWith(@this, head);
  165. /// <summary>将字节数组转换为 Base64 字符串。</summary>
  166. public static string Base64(this byte[] @this) => BytesUtility.ToBase64(@this);
  167. /// <summary>获取 MD5 值。</summary>
  168. public static byte[] MD5(params byte[] @this) => BytesUtility.MD5(@this);
  169. /// <summary>获取 SHA1 值。</summary>
  170. public static byte[] SHA1(params byte[] @this) => BytesUtility.SHA1(@this);
  171. /// <summary>获取 SHA256 值。</summary>
  172. public static byte[] SHA256(params byte[] @this) => BytesUtility.SHA256(@this);
  173. /// <summary>将字节数组转换为文本,默认为 UTF-8。</summary>
  174. public static string Text(this byte[] @this, Encoding encoding = null) => TextUtility.FromBytes(@this, encoding);
  175. /// <summary>为字节数组增加字节。</summary>
  176. public static byte[] Append(this byte[] @this, params byte[] bytes) => BytesUtility.Merge(@this, bytes);
  177. /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据(指定为 0 将不限制检查长度)。</summary>
  178. public static bool IsUTF8(this byte[] @this, int checkLength = 1048576) => TextUtility.IsUTF8(@this, checkLength, null);
  179. /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
  180. public static bool ContainsBOM(this byte[] @this) => TextUtility.ContainsBOM(@this);
  181. #endregion
  182. #region DateTime
  183. /// <summary>获取毫秒时间戳。</summary>
  184. public static long Stamp(this DateTime @this, bool byMilliseconds = true) => ClockUtility.Stamp(@this, byMilliseconds);
  185. /// <summary>转换为易于阅读的文本。</summary>
  186. /// <remarks>格式:1970-01-01 00:00:00.000</remarks>
  187. public static string Lucid(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => ClockUtility.Lucid(@this, date, time, seconds, milliseconds);
  188. /// <summary>转换为紧凑的文本。</summary>
  189. public static string Compact(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => ClockUtility.Compact(@this, date, time, seconds, milliseconds);
  190. /// <summary>当前 DateTime 为闰年。</summary>
  191. public static bool LeapYear(this DateTime @this) => ClockUtility.IsLeapYear(@this);
  192. /// <summary>从毫秒时间戳获取 DateTime 对象。发生异常且不允许异常时将返回 1970-01-01 00:00:00.000。</summary>
  193. /// <exception cref="ArgumentOutOfRangeException"></exception>
  194. public static DateTime DateTime(this long stamp, DateTimeKind kind = DateTimeKind.Unspecified, bool throwException = true) => ClockUtility.FromStamp(stamp, kind, throwException);
  195. #region Nullable
  196. /// <summary>转换为易于阅读的文本。</summary>
  197. /// <remarks>格式:1970-01-01 00:00:00.000</remarks>
  198. public static string Lucid(this DateTime? @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => @this == null ? default : ClockUtility.Lucid(@this.Value, date, time, seconds, milliseconds);
  199. /// <summary>转换为紧凑的文本。</summary>
  200. public static string Compact(this DateTime? @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => @this == null ? default : ClockUtility.Compact(@this.Value, date, time, seconds, milliseconds);
  201. /// <summary>获取毫秒时间戳。</summary>
  202. public static long Stamp(this DateTime? @this, bool byMilliseconds = true) => @this == null ? default : ClockUtility.Stamp(@this.Value, byMilliseconds);
  203. /// <summary>转换为易于阅读的文本。</summary>
  204. /// <remarks>格式:1970-01-01 00:00:00.000</remarks>
  205. public static string Lucid(this Class<DateTime> @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => @this == null ? default : ClockUtility.Lucid(@this.Value, date, time, seconds, milliseconds);
  206. /// <summary>转换为紧凑的文本。</summary>
  207. public static string Compact(this Class<DateTime> @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => @this == null ? default : ClockUtility.Compact(@this.Value, date, time, seconds, milliseconds);
  208. /// <summary>获取毫秒时间戳。</summary>
  209. public static long Stamp(this Class<DateTime> @this, bool byMilliseconds = true) => @this == null ? default : ClockUtility.Stamp(@this.Value, byMilliseconds);
  210. #endregion
  211. #endregion
  212. #region ArrayBuilder
  213. /// <summary>拼接 <see cref="char"/> 为字符串。</summary>
  214. /// <returns>连接后的字符串,返回值不为 NULL。</returns>
  215. public static string Text(this ArrayBuilder<char> ab) => ArrayBuilder<char>.Text(ab);
  216. /// <summary>拼接 <see cref="char"/> 为字符串。</summary>
  217. /// <returns>连接后的字符串,返回值不为 NULL。</returns>
  218. /// <exception cref="ArgumentOutOfRangeException"></exception>
  219. public static string Text(this ArrayBuilder<char> ab, int start, int count) => ArrayBuilder<char>.Text(ab, start, count);
  220. /// <summary>使用指定的分隔符连接 <see cref="ArrayBuilder{T}"/> 中的元素,指定分隔符为 NULL 将忽略分隔符。</summary>
  221. /// <returns>连接后的字符串,返回值不为 NULL。</returns>
  222. public static string Join(this ArrayBuilder<string> ab, string separator = null) => ArrayBuilder<string>.Join(ab, separator);
  223. /// <summary>使用指定的分隔符连接 <see cref="ArrayBuilder{T}"/> 中的元素,指定分隔符为 NULL 将忽略分隔符。</summary>
  224. /// <returns>连接后的字符串,返回值不为 NULL。</returns>
  225. /// <exception cref="ArgumentOutOfRangeException"></exception>
  226. public static string Join(this ArrayBuilder<string> ab, string separator, int startIndex, int maxCount) => ArrayBuilder<string>.Join(ab, separator, startIndex, maxCount);
  227. #endregion
  228. #region Json
  229. /// <summary>Json 对象可用。</summary>
  230. public static bool Available(this Json @this) => @this != null && @this.Available;
  231. /// <summary>生成 JSON 对象,失败时返回 NULL。</summary>
  232. /// <param name="this">将要解析的对象。</param>
  233. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  234. /// <param name="depth">解析深度。</param>
  235. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  236. public static Json Json(this IDictionary @this, bool lowerCase = false, int depth = -1, bool force = false) => Apewer.Json.From(@this, lowerCase, depth, force);
  237. /// <summary>解析实现 IList 的对象为 Json 对象,失败时返回 Null。</summary>
  238. /// <param name="this">将要解析的对象。</param>
  239. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  240. /// <param name="depth">解析深度。</param>
  241. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  242. public static Json Json(this IList @this, bool lowerCase = false, int depth = -1, bool force = false) => Apewer.Json.From(@this, lowerCase, depth, force);
  243. /// <summary>
  244. /// <para>解析对象为 Json 对象,包含所有公共属性,失败时返回 Null。</para>
  245. /// <para>String 对象将解析文本;Json 对象将返回实例;String 对象将解析文本;实现 IDictionary 或 IList 的对象将解析内容。</para>
  246. /// </summary>
  247. /// <param name="this">将要解析的对象。</param>
  248. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  249. /// <param name="depth">解析深度。</param>
  250. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  251. /// <exception cref="System.Exception"></exception>
  252. public static Json Json(object @this, bool lowerCase = false, int depth = -1, bool force = false) => Apewer.Json.From(@this, lowerCase, depth, force);
  253. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  254. /// <param name="this">将要解析的对象。</param>
  255. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  256. /// <param name="ignoreChars">忽略的属性名称字符。</param>
  257. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  258. public static T Object<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) where T : class, new() => Apewer.Json.Object<T>(@this, ignoreCase, ignoreChars, force);
  259. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  260. /// <param name="this">将要解析的对象。</param>
  261. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  262. /// <param name="ignoreChars">忽略的属性名称字符。</param>
  263. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  264. public static T[] Array<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) => Apewer.Json.Array<T>(@this, ignoreCase, ignoreChars, force);
  265. /// <summary>设置属性名称为小写。</summary>
  266. public static Json Lower(this Json @this) => Apewer.Json.Lower(@this);
  267. /// <summary>设置属性名称为驼峰形式。</summary>
  268. public static Json Camel(this Json @this) => Apewer.Json.Camel(@this);
  269. #endregion
  270. #region Logger
  271. /// <summary>记录异常。</summary>
  272. public static void Exception(this Logger logger, object sender, Exception exception) => logger?.InnerException(sender, exception);
  273. /// <summary>记录错误。多个 Content 参数将以“ | ”分隔。</summary>
  274. public static void Error(this Logger logger, object sender, params object[] content) => logger?.Colorful(sender, "Error", ConsoleColor.DarkRed, content, null);
  275. /// <summary>记录警告。多个 Content 参数将以“ | ”分隔。</summary>
  276. public static void Warning(this Logger logger, object sender, params object[] content) => logger?.Colorful(sender, "Warning", ConsoleColor.DarkYellow, content, null);
  277. /// <summary>记录警告。多个 Content 参数将以“ | ”分隔。</summary>
  278. public static void Info(this Logger logger, object sender, params object[] content) => logger?.Colorful(sender, "Info", ConsoleColor.DarkBlue, content, null);
  279. /// <summary>记录文本。多个 Content 参数将以“ | ”分隔。</summary>
  280. public static void Text(this Logger logger, object sender, params object[] content) => logger?.Colorful(sender, null, null, content, null);
  281. /// <summary>记录调试。多个 Content 参数将以“ | ”分隔。</summary>
  282. [Conditional("DEBUG")]
  283. public static void Debug(this Logger logger, object sender, params object[] content) => logger?.Colorful(sender, null, null, content, null);
  284. #endregion
  285. #region Stream
  286. /// <summary>重置流的位置到开始位置。</summary>
  287. public static bool ResetPosition(this Stream @this) => BytesUtility.ResetPosition(@this);
  288. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的字节数。</summary>
  289. public static long Read(this Stream @this, Stream destination, Action<long> progress = null) => BytesUtility.Read(@this, destination, progress);
  290. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的字节数。</summary>
  291. public static long Read(this Stream @this, Stream destination, Func<long, bool> progress) => BytesUtility.Read(@this, destination, progress);
  292. /// <summary>读取源流中的数据,获取写入的字节。</summary>
  293. public static byte[] Read(this Stream @this, bool dispose) => BytesUtility.Read(@this, 1024, dispose);
  294. /// <summary>读取源流中的数据。</summary>
  295. public static byte[] Read(this Stream @this, int buffer = 1024, bool dispose = false) => BytesUtility.Read(@this, buffer, dispose);
  296. /// <summary>向流写入数据。</summary>
  297. /// <param name="this">源流。</param>
  298. /// <param name="bytes">要写入的数据。</param>
  299. public static long Write(this Stream @this, params byte[] bytes) => BytesUtility.Write(@this, bytes);
  300. /// <summary>读取源流中的数据,并将数据写入当前流,获取写入的字节数。</summary>
  301. /// <param name="this">目标流。</param>
  302. /// <param name="source">源流。</param>
  303. public static long Write(this Stream @this, Stream source) => BytesUtility.Read(source, @this);
  304. /// <summary>获取 MD5 值。</summary>
  305. public static byte[] MD5(this Stream @this) => BytesUtility.MD5(@this);
  306. /// <summary>获取 SHA1 值。</summary>
  307. public static byte[] SHA1(this Stream @this) => BytesUtility.SHA1(@this);
  308. #if !NET20
  309. /// <summary>获取 SHA256 值。</summary>
  310. public static byte[] SHA256(this Stream @this) => BytesUtility.SHA256(@this);
  311. #endif
  312. #endregion
  313. #region Rrflection
  314. /// <summary>判断指定类型具有特性。</summary>
  315. public static bool Contains<T>(this ICustomAttributeProvider @this, bool inherit = false) where T : Attribute => RuntimeUtility.Contains<T>(@this, inherit);
  316. #endregion
  317. #region Collection
  318. /// <summary>添加多个元素。</summary>
  319. public static void Add<T>(this List<T> @this, params T[] items)
  320. {
  321. if (@this != null && items != null) @this.AddRange(items);
  322. }
  323. /// <summary>添加元素。</summary>
  324. public static bool Add<TKey, TValue>(this IList<KeyValuePair<TKey, TValue>> @this, TKey key, TValue value) => CollectionUtility.Add<TKey, TValue>(@this, key, value);
  325. /// <summary>判断集合为空。</summary>
  326. public static bool IsEmpty<T>(this IEnumerable<T> @this) => CollectionUtility.IsEmpty(@this);
  327. /// <summary>判断集合存在元素。</summary>
  328. public static bool NotEmpty<T>(this IEnumerable<T> @this) => CollectionUtility.NotEmpty(@this);
  329. /// <summary>检查集合是否包含 item。</summary>
  330. public static bool Contains<T>(this IEnumerable<T> @this, T item) => CollectionUtility.Contains(@this, item);
  331. /// <summary>获取 item 在集合中的偏移位置,不存在时返回 -1。</summary>
  332. public static int IndexOf<T>(this IEnumerable<T> objects, T item) => CollectionUtility.IndexOf(objects, item);
  333. /// <summary>获取集合中元素的数量。</summary>
  334. public static int Count<T>(this IEnumerable<T> @this) => CollectionUtility.Count(@this);
  335. /// <summary>对元素去重,且去除 NULL 值。</summary>
  336. public static T[] Distinct<T>(this IEnumerable<T> @this) => CollectionUtility.Distinct(@this);
  337. /// <summary>获取可枚举集合的部分元素。</summary>
  338. public static T[] Slice<T>(this IEnumerable<T> @this, int start = 0, int count = -1, Func<T> stuffer = null) => CollectionUtility.Slice<T>(@this, start, count, stuffer);
  339. /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
  340. public static List<T> List<T>(this IEnumerable<T> @this, bool excludeNull = false) => CollectionUtility.List<T>(@this, excludeNull);
  341. /// <summary>安全转换为 &lt;<typeparamref name="T"/>&gt;[] 对象。可指定排除 NULL 值元素。</summary>
  342. public static T[] Array<T>(IEnumerable<T> @this, bool excludeNull = false) => CollectionUtility.Array<T>(@this, excludeNull);
  343. /// <summary>对列表中的元素排序。</summary>
  344. public static List<T> Sort<T>(this List<T> @this, Func<T, T, int> comparison) => CollectionUtility.Sort(@this, comparison);
  345. /// <summary>对字典中的键排序。</summary>
  346. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(this Dictionary<TKey, TValue> @this, Func<TKey, TKey, int> comparison) => CollectionUtility.SortKey(@this, comparison);
  347. /// <summary>对字典中的键排序。</summary>
  348. public static Dictionary<TKey, TValue> SortKey<TKey, TValue>(this Dictionary<TKey, TValue> @this) where TKey : IComparable<TKey> => CollectionUtility.SortKey(@this, (a, b) => a.CompareTo(b));
  349. /// <summary>对字典中的值排序。</summary>
  350. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(this Dictionary<TKey, TValue> @this, Func<TValue, TValue, int> comparison) => CollectionUtility.SortValue(@this, comparison);
  351. /// <summary>对字典中的值排序。</summary>
  352. public static Dictionary<TKey, TValue> SortValue<TKey, TValue>(this Dictionary<TKey, TValue> @this) where TValue : IComparable<TValue> => CollectionUtility.SortValue(@this, (a, b) => a.CompareTo(b));
  353. /// <summary>获取集合中的第一个元素。可指定失败时的默认返回值。</summary>
  354. public static T First<T>(this IEnumerable<T> collection, T failed = default(T)) => CollectionUtility.First(collection, failed);
  355. /// <summary>获取集合中的最后一个元素。可指定失败时的默认返回值。</summary>
  356. public static T Last<T>(this IEnumerable<T> collection, T failed = default(T)) => CollectionUtility.Last(collection, failed);
  357. /// <summary>生成 StringPairs 对象实例为副本。</summary>
  358. public static StringPairs StringPairs(this NameValueCollection @this) => Apewer.StringPairs.From(@this);
  359. /// <summary>对数组排序。</summary>
  360. /// <exception cref="NullReferenceException"></exception>
  361. public static void Sort<T>(this T[] @this, Func<T, T, int> func) { if (@this != null && func != null) System.Array.Sort(@this, new Comparison<T>(func)); }
  362. /// <summary>对数组升序排序。</summary>
  363. /// <exception cref="NullReferenceException"></exception>
  364. public static void Ascend<T>(this T[] @this) where T : IComparable<T> { if (@this != null) Sort(@this, (a, b) => a.CompareTo(b)); }
  365. /// <summary>对数组升序排序。</summary>
  366. /// <exception cref="NullReferenceException"></exception>
  367. public static void Ascend<T, TProp>(this T[] @this, Func<T, TProp> func) where TProp : IComparable<TProp> { if (@this != null && func != null) Sort(@this, (a, b) => func(a).CompareTo(func(b))); }
  368. /// <summary>对数组降序排序。</summary>
  369. /// <exception cref="NullReferenceException"></exception>
  370. public static void Descend<T>(this T[] @this) where T : IComparable<T> { if (@this != null) Sort(@this, (a, b) => 0 - a.CompareTo(b)); }
  371. /// <summary>对数组降序排序。</summary>
  372. /// <exception cref="NullReferenceException"></exception>
  373. public static void Descend<T, TProp>(this T[] @this, Func<T, TProp> func) where TProp : IComparable<TProp> { if (@this != null && func != null) Sort(@this, (a, b) => 0 - func(a).CompareTo(func(b))); }
  374. #endregion
  375. #region Sets
  376. /// <summary>解析源对象。</summary>
  377. public static Dictionary<string, object> Origin(this ObjectSet instance) => instance == null ? null : instance.Origin;
  378. /// <summary>解析源对象。</summary>
  379. public static Dictionary<string, T> Origin<T>(this ObjectSet<T> instance) => instance == null ? null : instance.Origin;
  380. /// <summary>清空元素。</summary>
  381. public static void Clear(this ObjectSet instance) => instance?.Origin?.Clear();
  382. /// <summary>解析源对象。</summary>
  383. public static Dictionary<string, string> Origin(this TextSet instance) => instance == null ? null : instance.Origin;
  384. /// <summary>清空元素。</summary>
  385. public static void Clear(this TextSet instance) => instance?.Origin?.Clear();
  386. #endregion
  387. #region Source
  388. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
  389. public static Class<DateTime> DateTime(this IQuery @this, int row, int column) => @this == null ? null : ClockUtility.DateTime(@this.Value(row, column));
  390. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
  391. public static Class<DateTime> DateTime(this IQuery @this, int row, string column) => @this == null ? null : ClockUtility.DateTime(@this.Value(row, column));
  392. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
  393. public static Int32 Int32(this IQuery @this, int row, int column) => @this == null ? 0 : NumberUtility.Int32(@this.Value(row, column));
  394. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
  395. public static Int32 Int32(this IQuery @this, int row, string column) => @this == null ? 0 : NumberUtility.Int32(@this.Value(row, column));
  396. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
  397. public static Int64 Int64(this IQuery @this, int row, int column) => @this == null ? 0L : NumberUtility.Int64(@this.Value(row, column));
  398. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
  399. public static Int64 Int64(this IQuery @this, int row, string column) => @this == null ? 0L : NumberUtility.Int64(@this.Value(row, column));
  400. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
  401. public static Decimal Decimal(this IQuery @this, int row, int column) => @this == null ? 0M : NumberUtility.Decimal(@this.Value(row, column));
  402. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
  403. public static Decimal Decimal(this IQuery @this, int row, string column) => @this == null ? 0M : NumberUtility.Decimal(@this.Value(row, column));
  404. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>>
  405. public static Double Double(this IQuery @this, int row, int column) => @this == null ? 0D : NumberUtility.Double(@this.Value(row, column));
  406. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>>
  407. public static Double Double(this IQuery @this, int row, string column) => @this == null ? 0D : NumberUtility.Double(@this.Value(row, column));
  408. /// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
  409. public static string Text(this IQuery @this, int row, int column) => @this == null ? null : TextUtility.Text(@this.Value(row, column));
  410. /// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
  411. public static string Text(this IQuery @this, int row, string column) => @this == null ? null : TextUtility.Text(@this.Value(row, column));
  412. /// <summary>转换 <see cref="System.Data.DataTable"/> 到 <see cref="ObjectSet{T}"/> 数组,每行记录为一个 ObjectSet 对象。</summary>
  413. /// <returns>当参数 table 无效时返回 0 长度的 <see cref="ObjectSet{T}"/> 数组。</returns>
  414. public static ObjectSet[] ObjectSet(this IQuery @this) => @this == null ? null : SourceUtility.ObjectSet(@this.Table);
  415. /// <summary>转换 <see cref="DataTable"/> 为 CSV 文本,不存在表时返回 NULL 值。可指定是否包含表头。</summary>
  416. public static string Csv(this IQuery query, bool withHead = false) => query == null ? null : SourceUtility.Csv(query.Table, withHead);
  417. #endregion
  418. #region Web
  419. /// <summary>获取参数,指定可能的参数名,默认将修剪参数值。</summary>
  420. /// <remarks>当从 URL 中获取参数时将解码。</remarks>
  421. public static string Parameter(this ApiRequest @this, params string[] names) => ApiUtility.Parameter(@this, true, names);
  422. /// <summary>设置 status 为 error,并设置 message 的内容。</summary>
  423. public static void Error(this ApiResponse @this, string message = "未知错误。") => ApiUtility.Error(@this, message);
  424. /// <summary>输出字节数组。</summary>
  425. public static void Bytes(this ApiResponse @this, byte[] bytes, string type = "application/octet-stream") => ApiUtility.Model(@this, new ApiBytesModel(bytes, type));
  426. /// <summary>输出 UTF-8 文本。</summary>
  427. public static void Text(this ApiResponse @this, string text, string contentType = "text/plain") => ApiUtility.Model(@this, new ApiTextModel(text, contentType));
  428. /// <summary>输出 Json 文本。</summary>
  429. public static void Json(this ApiResponse @this, Json json, bool indented = true, bool camel = false) => ApiUtility.Model(@this, new ApiJsonModel(json, camel, indented));
  430. /// <summary>输出文件。</summary>
  431. public static void File(this ApiResponse @this, string path) => ApiUtility.Model(@this, new ApiFileModel(path));
  432. /// <summary>重定向。</summary>
  433. public static void Redirect(this ApiResponse @this, string location) => ApiUtility.Model(@this, new ApiRedirectModel() { Location = location });
  434. #endregion
  435. }