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.

591 lines
27 KiB

  1. using Apewer;
  2. using Apewer.Internals;
  3. using Apewer.Source;
  4. using Apewer.Surface;
  5. using Apewer.Web;
  6. using System;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Reflection;
  11. using System.Runtime.CompilerServices;
  12. using System.Text;
  13. #if NETFX || NETCORE
  14. using System.Windows.Forms;
  15. #endif
  16. /// <summary>扩展方法。</summary>
  17. public static class Extensions
  18. {
  19. #region Class Utility
  20. /// <summary>克隆对象,创建新对象。可指定包含对象的属性和字段。</summary>
  21. public static T Clone<T>(this T @this, T failed = default(T), bool properties = true, bool fields = false) where T : new()
  22. {
  23. return ClassUtility.Clone(@this, failed, properties, fields);
  24. }
  25. /// <summary>解析源对象。</summary>
  26. public static Dictionary<string, string> GetOrigin(this TextSet @this)
  27. {
  28. return ClassUtility.GetOrigin(@this);
  29. }
  30. /// <summary>解析源对象。</summary>
  31. public static Dictionary<string, object> GetOrigin(this ObjectSet @this)
  32. {
  33. return ClassUtility.GetOrigin(@this);
  34. }
  35. /// <summary>解析源对象。</summary>
  36. public static Dictionary<string, T> GetOrigin<T>(this ObjectSet<T> @this)
  37. {
  38. return ClassUtility.GetOrigin(@this);
  39. }
  40. /// <summary>调用 Get 方法。</summary>
  41. public static object Get(this PropertyInfo @this, object instance)
  42. {
  43. return ClassUtility.InvokeGet<object>(instance, @this);
  44. }
  45. /// <summary>调用 Set 方法。</summary>
  46. public static void Set(this PropertyInfo @this, object instance, object value)
  47. {
  48. ClassUtility.InvokeSet<object>(instance, @this, value);
  49. }
  50. /// <summary>调用 Get 方法。</summary>
  51. public static T Get<T>(this PropertyInfo @this, object instance)
  52. {
  53. return ClassUtility.InvokeGet<T>(instance, @this);
  54. }
  55. /// <summary>调用 Set 方法。</summary>
  56. public static void Set<T>(this PropertyInfo @this, object instance, T value)
  57. {
  58. ClassUtility.InvokeSet<T>(instance, @this, value);
  59. }
  60. /// <summary>调用方法。</summary>
  61. /// <exception cref="ArgumentException"></exception>
  62. /// <exception cref="InvalidOperationException"></exception>
  63. /// <exception cref="MethodAccessException"></exception>
  64. /// <exception cref="NotSupportedException"></exception>
  65. /// <exception cref="TargetException"></exception>
  66. /// <exception cref="TargetInvocationException"></exception>
  67. /// <exception cref="TargetParameterCountException"></exception>
  68. public static object Invoke(this MethodInfo @this, object instace, params object[] parameters)
  69. {
  70. return ClassUtility.InvokeMethod(instace, @this, parameters);
  71. }
  72. /// <summary>遍历公开属性。</summary>
  73. public static void ForEachProperties(this Type @this, Action<PropertyInfo> action)
  74. {
  75. ClassUtility.ForEachPublicProperties(@this, action);
  76. }
  77. /// <summary>判断静态属性。</summary>
  78. public static bool IsStatic(this PropertyInfo @this)
  79. {
  80. return ClassUtility.IsStatic(@this);
  81. }
  82. /// <summary>判断类型。</summary>
  83. public static bool TypeEquals<T>(this object @this)
  84. {
  85. return ClassUtility.TypeEquals(@this, typeof(T));
  86. }
  87. #endregion
  88. #region Number
  89. private static bool Equals<T>(this T @this, T value) where T : IComparable<T> => @this.CompareTo(value) == 0;
  90. /// <summary></summary>
  91. public static bool IsZero(this decimal @this) => @this.Equals(0M);
  92. /// <summary></summary>
  93. public static bool IsZero(this double @this) => @this.Equals(0D);
  94. /// <summary></summary>
  95. public static bool IsZero(this float @this) => @this.Equals(0F);
  96. /// <summary></summary>
  97. public static bool NotZero(this decimal @this) => !@this.Equals(0M);
  98. /// <summary></summary>
  99. public static bool NotZero(this double @this) => !@this.Equals(0D);
  100. /// <summary></summary>
  101. public static bool NotZero(this float @this) => !@this.Equals(0F);
  102. /// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
  103. public static T RestrictValue<T>(this T @this, T min, T max) where T : IComparable => NumberUtility.RestrictValue<T>(@this, min, max);
  104. /// <summary></summary>
  105. [CLSCompliant(false)]
  106. public static Byte ToByte(this IConvertible @this) => @this.ToByte(null);
  107. /// <summary></summary>
  108. [CLSCompliant(false)]
  109. public static Int32 ToInt32(this IConvertible @this) => @this.ToInt32(null);
  110. /// <summary></summary>
  111. [CLSCompliant(false)]
  112. public static Int64 ToInt64(this IConvertible @this) => @this.ToInt64(null);
  113. /// <summary></summary>
  114. [CLSCompliant(false)]
  115. public static Double ToDouble(this IConvertible @this) => @this.ToDouble(null);
  116. /// <summary></summary>
  117. [CLSCompliant(false)]
  118. public static Decimal ToDecimal(this IConvertible @this) => @this.ToDecimal(null);
  119. #endregion
  120. #region String、StringBuilder
  121. /// <summary></summary>
  122. public static Int32 ToInt32(this string @this) => TextUtility.GetInt32(@this);
  123. /// <summary></summary>
  124. public static Int64 ToInt64(this string @this) => TextUtility.GetInt64(@this);
  125. /// <summary></summary>
  126. public static Decimal ToDecimal(this string @this) => TextUtility.GetDecimal(@this);
  127. /// <summary></summary>
  128. public static Double ToDouble(this string @this) => TextUtility.GetDouble(@this);
  129. /// <summary>将文本转换为字节数组,默认为 UTF-8。</summary>
  130. public static byte[] ToBinary(this string @this, Encoding encoding = null) => TextUtility.ToBinary(@this, encoding);
  131. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  132. public static bool IsEmpty(this string @this) => TextUtility.IsEmpty(@this);
  133. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  134. public static bool NotEmpty(this string @this) => TextUtility.NotEmpty(@this);
  135. /// <summary>验证字符串为 NULL、为空或无实际内容。</summary>
  136. /// <param name="this"></param>
  137. /// <param name="allCases">所有情况,包含全角。</param>
  138. public static bool IsBlank(this string @this, bool allCases = false) => TextUtility.IsBlank(@this, allCases);
  139. /// <summary>验证字符串含有实际内容。</summary>
  140. /// <param name="this"></param>
  141. /// <param name="allCases">所有情况,包含全角。</param>
  142. public static bool NotBlank(this string @this, bool allCases = false) => TextUtility.NotBlank(@this, allCases);
  143. /// <summary>将文本转换为字节数组,默认为 UTF-8。</summary>
  144. public static byte[] GetBytes(this string @this, Encoding encoding = null) => TextUtility.ToBinary(@this, encoding);
  145. /// <summary>用指定的分隔符拆分文本。</summary>
  146. public static string[] Split(this string @this, string separator) => TextUtility.Split(@this, separator);
  147. /// <summary>使用多个分隔符切分字符串,得到多个子字符串。</summary>
  148. public static string[] Split(this string @this, params char[] separators) => TextUtility.Split(@this, separators);
  149. /// <summary>返回此字符串的安全键副本。</summary>
  150. public static string SafeKey(this string @this, int maxLength = 255) => TextUtility.SafeKey(@this, maxLength);
  151. /// <summary>移除字符串前后的空白。</summary>
  152. public static string SafeTrim(this string @this) => TextUtility.Trim(@this);
  153. /// <summary>移除字符串前后的空白。</summary>
  154. /// <param name="this"></param>
  155. /// <param name="allCases">所有情况,全角空格将被去除。</param>
  156. public static string SafeTrim(this string @this, bool allCases) => TextUtility.Trim(@this, allCases);
  157. /// <summary>返回此字符串转换为小写形式的副本。</summary>
  158. public static string SafeLower(this string @this) => TextUtility.ToLower(@this);
  159. /// <summary>返回此字符串转换为大写形式的副本。</summary>
  160. public static string SafeUpper(this string @this) => TextUtility.ToUpper(@this);
  161. /// <summary>约束字符串用于 Key。</summary>
  162. public static string RestrictKey(this string @this) => TextUtility.RestrictGuid(TextUtility.ToLower(@this));
  163. /// <summary>约束字符串长度范围,超出的部分将被截取去除。</summary>
  164. public static string RestrictLength(this string @this, int length) => TextModifier.RestrictLength(@this, length);
  165. /// <summary>约束字符串长度为 32,超出的部分将被截取去除。</summary>
  166. public static string Restrict32(this string @this) => TextModifier.RestrictLength(@this, 32);
  167. /// <summary>约束字符串长度为 255,超出的部分将被截取去除。</summary>
  168. public static string Restrict255(this string @this) => TextModifier.RestrictLength(@this, 255);
  169. /// <summary>约束字符串长度为 2000,超出的部分将被截取去除。</summary>
  170. public static string Restrict2000(this string @this) => TextModifier.RestrictLength(@this, 2000);
  171. /// <summary>追加字符串。</summary>
  172. public static string Append(this string @this, params object[] text) => TextUtility.Merge(@this, TextUtility.Merge(text));
  173. /// <summary>追加文本。</summary>
  174. public static void Append(this StringBuilder @this, params object[] text) => TextUtility.Append(@this, text);
  175. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  176. public static string AntiInject(this string @this, int length = -1, string blacklist = null) => TextUtility.AntiInject(@this, length, blacklist);
  177. /// <summary>将 Base64 字符串转换为字节数组。</summary>
  178. public static byte[] AntiBase64(this string @this) => BinaryUtility.FromBase64(@this);
  179. /// <summary>对 URL 编码。</summary>
  180. public static string EncodeUrl(this string @this) => UrlEncoding.Encode(@this);
  181. /// <summary>对 URL 解码。</summary>
  182. public static string DecodeUrl(this string @this) => UrlEncoding.Decode(@this);
  183. #endregion
  184. #region Byte[]
  185. /// <summary>将字节数组格式化为大写十六进制字符串。<para>例:D41D8CD98F00B204E9800998ECF8427E</para></summary>
  186. public static string ToX2(this byte[] @this) => BinaryUtility.ToX2(@this);
  187. /// <summary>克隆字节数组。当源为 NULL 时,将获取零元素字节数组。</summary>
  188. public static byte[] Clone(this byte[] @this) => BinaryUtility.Clone(@this);
  189. /// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
  190. public static bool StartsWith(this byte[] @this, params byte[] head) => BinaryUtility.StartsWith(@this, head);
  191. /// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
  192. public static bool EndsWith(this byte[] @this, params byte[] head) => BinaryUtility.EndsWith(@this, head);
  193. /// <summary>将字节数组转换为 Base64 字符串。</summary>
  194. public static string ToBase64(this byte[] @this) => BinaryUtility.ToBase64(@this);
  195. /// <summary>获取 MD5 值。</summary>
  196. public static byte[] GetMD5(params byte[] @this) => BinaryUtility.MD5(@this);
  197. /// <summary>获取 SHA1 值。</summary>
  198. public static byte[] GetSHA1(params byte[] @this) => BinaryUtility.SHA1(@this);
  199. #if !NET20
  200. /// <summary>获取 SHA256 值。</summary>
  201. public static byte[] GetSHA256(params byte[] @this) => BinaryUtility.SHA256(@this);
  202. #endif
  203. /// <summary>将字节数组转换为文本,默认为 UTF-8。</summary>
  204. public static string GetString(this byte[] @this, Encoding encoding = null) => TextUtility.FromBinary(@this, encoding);
  205. /// <summary>将字节数组转换为文本,默认为 UTF-8。</summary>
  206. public static string ToText(this byte[] @this, Encoding encoding = null) => TextUtility.FromBinary(@this, encoding);
  207. /// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
  208. public static byte[] AddTextBom(this byte[] @this) => BinaryUtility.AddTextBom(@this);
  209. /// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
  210. public static byte[] WipeTextBom(this byte[] @this) => BinaryUtility.WipeTextBom(@this);
  211. /// <summary>为字节数组增加字节。</summary>
  212. public static byte[] Append(this byte[] @this, params byte[] bytes) => BinaryUtility.Append(@this, bytes);
  213. /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
  214. /// <param name="bytes">要检查的字节数组。</param>
  215. /// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
  216. public static bool IsUTF8(this byte[] @this, int checkLength = 1048576) => BinaryUtility.IsUTF8(@this, checkLength, null);
  217. /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
  218. public static bool ContainsBOM(this byte[] @this) => BinaryUtility.ContainsBOM(@this);
  219. #endregion
  220. #region DateTime
  221. /// <summary>获取毫秒时间戳。</summary>
  222. public static long GetStamp(this DateTime @this) => DateTimeUtility.GetStamp(@this);
  223. /// <summary>获取毫秒时间戳。</summary>
  224. public static long ToStamp(this DateTime @this) => DateTimeUtility.ToStamp(@this);
  225. /// <summary>转换为易于阅读的文本。</summary>
  226. public static string ToLucid(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => DateTimeUtility.ToLucid(@this, date, time, seconds, milliseconds);
  227. /// <summary>转换为紧凑的文本。</summary>
  228. public static string ToCompact(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true) => DateTimeUtility.ToCompact(@this, date, time, seconds, milliseconds);
  229. /// <summary>当前 DateTime 为闰年。</summary>
  230. public static bool IsLeapYear(this DateTime @this) => DateTimeUtility.IsLeapYear(DateTimeUtility.GetDateTime(@this).Year);
  231. #endregion
  232. #region Json
  233. /// <summary>生成 JSON 对象,失败时返回 NULL。</summary>
  234. /// <param name="this">将要解析的对象。</param>
  235. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  236. /// <param name="depth">解析深度。</param>
  237. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  238. public static Json ToJson(this IDictionary @this, bool lowerCase = false, int depth = -1, bool force = false) => Json.Parse(@this, lowerCase, depth, force);
  239. /// <summary>解析实现 IList 的对象为 Json 对象,失败时返回 Null。</summary>
  240. /// <param name="this">将要解析的对象。</param>
  241. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  242. /// <param name="depth">解析深度。</param>
  243. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  244. public static Json ToJson(this IList @this, bool lowerCase = false, int depth = -1, bool force = false) => Json.Parse(@this, lowerCase, depth, force);
  245. /// <summary>
  246. /// <para>解析对象为 Json 对象,包含所有公共属性,失败时返回 Null。</para>
  247. /// <para>String 对象将解析文本;Json 对象将返回实例;String 对象将解析文本;实现 IDictionary 或 IList 的对象将解析内容。</para>
  248. /// </summary>
  249. /// <param name="this">将要解析的对象。</param>
  250. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  251. /// <param name="depth">解析深度。</param>
  252. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  253. /// <exception cref="System.Exception"></exception>
  254. public static Json ToJson(object @this, bool lowerCase = false, int depth = -1, bool force = false) => Json.Parse(@this, lowerCase, depth, force);
  255. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  256. /// <param name="this">将要解析的对象。</param>
  257. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  258. /// <param name="ignoreChars">忽略的属性名称字符。</param>
  259. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  260. public static T FillObject<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) where T : class, new() => Json.FillObject<T>(@this, ignoreCase, ignoreChars, force);
  261. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  262. /// <param name="this">将要解析的对象。</param>
  263. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  264. /// <param name="ignoreChars">忽略的属性名称字符。</param>
  265. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  266. public static List<T> FillArray<T>(this Json @this, bool ignoreCase = true, string ignoreChars = null, bool force = false) where T : class, new() => Json.FillArray<T>(@this, ignoreCase, ignoreChars, force);
  267. /// <summary>设置属性名称为小写。</summary>
  268. public static Json ToLower(this Json @this) => Json.ToLower(@this);
  269. #endregion
  270. #region Stream
  271. /// <summary>重置流的位置到开始位置。</summary>
  272. public static bool ResetPosition(this Stream @this) => StreamHelper.ResetPosition(@this);
  273. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的字节数。</summary>
  274. public static long Read(this Stream @this, Stream destination, Action<long> progress = null) => BinaryUtility.Read(@this, destination, progress);
  275. /// <summary>读取源流中的数据,获取写入的字节。</summary>
  276. public static byte[] Read(this Stream @this, bool dispose = false) => BinaryUtility.Read(@this, dispose);
  277. /// <summary>向流写入数据。</summary>
  278. /// <param name="this">源流。</param>
  279. /// <param name="bytes">要写入的数据。</param>
  280. public static long Write(this Stream @this, params byte[] bytes) => BinaryUtility.Write(@this, bytes);
  281. /// <summary>读取源流中的数据,并将数据写入当前流,获取写入的字节数。</summary>
  282. /// <param name="this">目标流。</param>
  283. /// <param name="source">源流。</param>
  284. public static long Write(this Stream @this, Stream source) => StreamHelper.Read(source, @this);
  285. /// <summary>获取 MD5 值。</summary>
  286. public static byte[] MD5(this Stream @this) => BinaryUtility.MD5(@this);
  287. /// <summary>获取 SHA1 值。</summary>
  288. public static byte[] SHA1(this Stream @this) => BinaryUtility.SHA1(@this);
  289. #if !NET20
  290. /// <summary>获取 SHA256 值。</summary>
  291. public static byte[] SHA256(this Stream @this) => BinaryUtility.SHA256(@this);
  292. #endif
  293. #endregion
  294. #region Type
  295. /// <summary>判断指定类型具有特性。</summary>
  296. public static bool ContainsAttribute<T>(this Type @this, bool inherit = false) where T : Attribute => ClassUtility.ContainsAttribute<T>(@this, inherit);
  297. #endregion
  298. #region IEnumerable、Array、List、Dictionary
  299. /// <summary></summary>
  300. public static IList<T> Add<T>(this IList<T> @this, IEnumerable<T> items)
  301. {
  302. if (@this != null && items != null)
  303. {
  304. foreach (var item in items) @this.Add(item);
  305. }
  306. return @this;
  307. }
  308. /// <summary></summary>
  309. public static IList<T> Add<T>(this IList<T> @this, params T[] items) => Add<T>(@this, items as IEnumerable<T>);
  310. /// <summary></summary>
  311. public static bool IsEmpty<T>(this IEnumerable<T> @this) => ClassUtility.IsEmpty(@this);
  312. /// <summary></summary>
  313. public static bool NotEmpty<T>(this IEnumerable<T> @this) => ClassUtility.NotEmpty(@this);
  314. /// <summary></summary>
  315. public static bool Contains<T>(this IEnumerable<T> @this, T cell) => ClassUtility.Contains(@this, cell);
  316. /// <summary>获取集合中元素的数量。</summary>
  317. public static int Count<T>(this IEnumerable<T> @this) => ClassUtility.Count(@this);
  318. /// <summary>对元素去重,且去除 NULL 值。</summary>
  319. public static T[] Distinct<T>(this IEnumerable<T> @this) => ClassUtility.Distinct(@this);
  320. /// <summary></summary>
  321. public static List<T> Sub<T>(this IEnumerable<T> @this, long start = 0, long count = -1, Func<T> stuffer = null) => ClassUtility.Sub<T>(@this, start, count, stuffer);
  322. /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
  323. /// <typeparam name="T"></typeparam>
  324. public static List<T> SafeList<T>(this IEnumerable<T> @this, bool excludeNull = false) => ClassUtility.ToList<T>(@this, excludeNull);
  325. /// <summary>升序排序。</summary>
  326. public static List<T> SortAscend<T>(this List<T> @this) where T : IComparable<T> => SortUtility.AscendT(@this);
  327. /// <summary>降序排序。</summary>
  328. public static List<T> SortDescend<T>(this List<T> @this) where T : IComparable<T> => SortUtility.DescendT<T>(@this);
  329. /// <summary>对 Key 排序。</summary>
  330. public static Dictionary<string, string> SortKey(this Dictionary<string, string> @this, bool ascend = true) => SortHelper.DictionaryStringString(@this, true, ascend);
  331. /// <summary>对 Value 排序。</summary>
  332. public static Dictionary<string, string> SortValue(this Dictionary<string, string> @this, bool ascend = true) => SortHelper.DictionaryStringString(@this, false, ascend);
  333. /// <summary>对 Key 排序。</summary>
  334. public static Dictionary<string, double> SortKey(this Dictionary<string, double> @this, bool ascend = true) => SortHelper.DictionaryStringDouble(@this, true, ascend);
  335. /// <summary>对 Value 排序。</summary>
  336. public static Dictionary<string, double> SortValue(this Dictionary<string, double> @this, bool ascend = true) => SortHelper.DictionaryStringDouble(@this, false, ascend);
  337. /// <summary>获取列表中的第一个 Item 对象。可指定失败时的默认返回值。</summary>
  338. public static T SafeFirst<T>(this IList<T> @this, T failed = default(T)) => (@this == null || @this.Count < 1) ? failed : @this[0];
  339. /// <summary>添加元素。</summary>
  340. /// <typeparam name="TKey"></typeparam>
  341. /// <typeparam name="TValue"></typeparam>
  342. /// <param name="this"></param>
  343. /// <param name="key"></param>
  344. /// <param name="value"></param>
  345. public static bool Add<TKey, TValue>(this IList<KeyValuePair<TKey, TValue>> @this, TKey key, TValue value)
  346. {
  347. if (@this == null) return false;
  348. @this.Add(new KeyValuePair<TKey, TValue>(key, value));
  349. return true;
  350. }
  351. #endregion
  352. #region Source
  353. /// <summary>为记录的 Key 属性设置新值。</summary>
  354. public static void SetNewKey(this Record @this) => Record.SetNewKey(@this);
  355. /// <summary>修补基本属性。</summary>
  356. public static void FixProperties(this Record @this) => Record.FixProperties(@this);
  357. /// <summary></summary>
  358. public static DateTime DateTime(this IQuery @this, int row, string column) => Query.DateTime(@this, row, column);
  359. /// <summary></summary>
  360. public static Int32 Int32(this IQuery @this, int row, string column) => @this == null ? 0 : ToInt32(@this.Text(row, column));
  361. /// <summary></summary>
  362. public static Int64 Int64(this IQuery @this, int row, string column) => @this == null ? 0L : ToInt64(@this.Text(row, column));
  363. /// <summary></summary>
  364. public static Decimal Decimal(this IQuery @this, int row, string column) => @this == null ? 0M : ToDecimal(@this.Text(row, column));
  365. /// <summary></summary>
  366. public static Double Double(this IQuery @this, int row, string column) => @this == null ? 0D : ToDouble(@this.Text(row, column));
  367. #endregion
  368. #region Web API
  369. #if NETFX
  370. /// <summary>获取查询字符串。</summary>
  371. public static string QueryString(this ApiRequest @this, string name, bool decode = false) => PageUtility.QueryString(name, decode);
  372. /// <summary>获取表单。</summary>
  373. public static string Form(this ApiRequest @this, string name) => PageUtility.RequestForm(name);
  374. #endif
  375. #if NETFX || NETCORE
  376. /// <summary>获取 URL 查询段,不存在的段为 NULL 值。可要求解码。</summary>
  377. public static string GetSegmentalUrl(this ApiRequest @this, int index = 3, bool decode = false) => WebUtility.GetSegmentalUrl(@this, index, decode);
  378. /// <summary>获取 URL 查询段,不存在的段为 NULL 值。可要求解码。</summary>
  379. public static string GetSegmental(this Uri @this, int index = 3, bool decode = false) => WebUtility.GetSegmental(@this, index, decode);
  380. /// <summary>获取参数,指定可能的参数名,从 URL 中获取参数时将解码。</summary>
  381. public static string GetParameter(this ApiRequest @this, params string[] names) => WebUtility.GetParameter(@this, names);
  382. /// <summary>设置 status 为 error,并设置 message 的内容。</summary>
  383. public static void Error(this ApiResponse @this, string message = "未知错误。") => ApiInternals.RespondError(@this, message);
  384. /// <summary>设置 status 为 error,并设置 message 的内容。</summary>
  385. public static void Error(this ApiResponse @this, Exception exception) => ApiInternals.RespondError(@this, exception);
  386. /// <summary>输出 UTF-8 文本。</summary>
  387. public static void Text(this ApiResponse @this, string content, string type = "text/plain") => ApiInternals.RespondText(@this, content, type);
  388. /// <summary>输出字节数组。</summary>
  389. public static void Binary(this ApiResponse @this, byte[] content, string type = "application/octet-stream") => ApiInternals.RespondBinary(@this, content, type);
  390. /// <summary>输出二进制。</summary>
  391. public static void Binary(this ApiResponse @this, Stream content, string type = "application/octet-stream") => ApiInternals.RespondBinary(@this, content, type);
  392. /// <summary>输出文件。</summary>
  393. public static void File(this ApiResponse @this, Stream stream, string name, string type = "application/octet-stream") => ApiInternals.RespondFile(@this, stream, name, type);
  394. /// <summary>重定向。</summary>
  395. public static void Redirect(this ApiResponse @this, string url) => ApiInternals.RespondRedirect(@this, url);
  396. /// <summary></summary>
  397. /// <typeparam name="T"></typeparam>
  398. /// <param name="this"></param>
  399. /// <returns></returns>
  400. public static T Use<T>(this ApiController @this) where T : ApiController, new()
  401. {
  402. var current = @this;
  403. var target = new T();
  404. if (current != null)
  405. {
  406. target.Request = current.Request;
  407. target.Response = current.Response;
  408. target.AfterInitialized?.Invoke();
  409. }
  410. return target;
  411. }
  412. /// <summary>设置响应,当发生错误时设置响应。返回错误信息。</summary>
  413. public static string Respond(this ApiResponse @this, IList list, bool lower = true, int depth = -1, bool force = false) => WebUtility.Respond(@this, list, lower, depth, force);
  414. /// <summary>设置响应,当发生错误时设置响应。返回错误信息。</summary>
  415. public static string Respond(this ApiResponse @this, Record record, bool lower = true) => WebUtility.Respond(@this, record, lower);
  416. #endif
  417. #endregion
  418. #region Surface
  419. #if NETFX || NETCORE
  420. /// <summary></summary>
  421. public static void Invoke(this Control @this, Action action, bool async = false) => FormsUtility.Invoke(@this, action, async);
  422. #endif
  423. #endregion
  424. }