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.

811 lines
30 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>
  90. {
  91. return @this.CompareTo(value) == 0;
  92. }
  93. /// <summary></summary>
  94. public static bool IsZero(this decimal @this)
  95. {
  96. return @this.Equals(0M);
  97. }
  98. /// <summary></summary>
  99. public static bool IsZero(this double @this)
  100. {
  101. return @this.Equals(0D);
  102. }
  103. /// <summary></summary>
  104. public static bool IsZero(this float @this)
  105. {
  106. return @this.Equals(0F);
  107. }
  108. /// <summary></summary>
  109. public static bool NotZero(this decimal @this)
  110. {
  111. return !@this.Equals(0M);
  112. }
  113. /// <summary></summary>
  114. public static bool NotZero(this double @this)
  115. {
  116. return !@this.Equals(0D);
  117. }
  118. /// <summary></summary>
  119. public static bool NotZero(this float @this)
  120. {
  121. return !@this.Equals(0F);
  122. }
  123. /// <summary>约束值范围,若源值不在范围中,则修改为接近的值。</summary>
  124. public static T RestrictValue<T>(this T @this, T min, T max) where T : IComparable
  125. {
  126. return NumberUtility.RestrictValue<T>(@this, min, max);
  127. }
  128. /// <summary></summary>
  129. [CLSCompliant(false)]
  130. public static Byte ToByte(this IConvertible @this)
  131. {
  132. return @this.ToByte(null);
  133. }
  134. /// <summary></summary>
  135. [CLSCompliant(false)]
  136. public static Int32 ToInt32(this IConvertible @this)
  137. {
  138. return @this.ToInt32(null);
  139. }
  140. /// <summary></summary>
  141. [CLSCompliant(false)]
  142. public static Int64 ToInt64(this IConvertible @this)
  143. {
  144. return @this.ToInt64(null);
  145. }
  146. /// <summary></summary>
  147. [CLSCompliant(false)]
  148. public static Double ToDouble(this IConvertible @this)
  149. {
  150. return @this.ToDouble(null);
  151. }
  152. /// <summary></summary>
  153. [CLSCompliant(false)]
  154. public static Decimal ToDecimal(this IConvertible @this)
  155. {
  156. return @this.ToDecimal(null);
  157. }
  158. #endregion
  159. #region String、StringBuilder
  160. /// <summary></summary>
  161. public static Int32 ToInt32(this string @this) { return TextUtility.GetInt32(@this); }
  162. /// <summary></summary>
  163. public static Int64 ToInt64(this string @this) { return TextUtility.GetInt64(@this); }
  164. /// <summary></summary>
  165. public static Decimal ToDecimal(this string @this) { return TextUtility.GetDecimal(@this); }
  166. /// <summary></summary>
  167. public static Double ToDouble(this string @this) { return TextUtility.GetDouble(@this); }
  168. /// <summary>将文本转换为字节数组,默认为 UTF-8。</summary>
  169. public static byte[] ToBinary(this string @this, Encoding encoding = null) { return TextUtility.ToBinary(@this, encoding); }
  170. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  171. public static bool IsEmpty(this string @this) { return TextUtility.IsEmpty(@this); }
  172. /// <summary>验证字符串为 NULL、为空或仅含空白。</summary>
  173. public static bool NotEmpty(this string @this) { return TextUtility.NotEmpty(@this); }
  174. /// <summary>验证字符串为 NULL、为空或无实际内容。</summary>
  175. /// <param name="this"></param>
  176. /// <param name="allCases">所有情况,包含全角。</param>
  177. public static bool IsBlank(this string @this, bool allCases = false) { return TextUtility.IsBlank(@this, allCases); }
  178. /// <summary>验证字符串含有实际内容。</summary>
  179. /// <param name="this"></param>
  180. /// <param name="allCases">所有情况,包含全角。</param>
  181. public static bool NotBlank(this string @this, bool allCases = false) { return TextUtility.NotBlank(@this, allCases); }
  182. /// <summary>将文本转换为字节数组,默认为 UTF-8。</summary>
  183. public static byte[] GetBytes(this string @this, Encoding encoding = null) { return TextUtility.ToBinary(@this, encoding); }
  184. /// <summary>用指定的分隔符拆分文本。</summary>
  185. public static string[] Split(this string @this, string separator) { return TextUtility.Split(@this, separator); }
  186. /// <summary>使用多个分隔符切分字符串,得到多个子字符串。</summary>
  187. public static string[] Split(this string @this, params char[] separators) { return TextUtility.Split(@this, separators); }
  188. /// <summary>返回此字符串的安全键副本。</summary>
  189. public static string SafeKey(this string @this) { return TextUtility.RestrictGuid(@this); }
  190. /// <summary>移除字符串前后的空白。</summary>
  191. public static string SafeTrim(this string @this) { return TextUtility.Trim(@this); }
  192. /// <summary>移除字符串前后的空白。</summary>
  193. /// <param name="this"></param>
  194. /// <param name="allCases">所有情况,全角空格将被去除。</param>
  195. public static string SafeTrim(this string @this, bool allCases) { return TextUtility.Trim(@this, allCases); }
  196. /// <summary>返回此字符串转换为小写形式的副本。</summary>
  197. public static string SafeLower(this string @this) { return TextUtility.ToLower(@this); }
  198. /// <summary>返回此字符串转换为大写形式的副本。</summary>
  199. public static string SafeUpper(this string @this) { return TextUtility.ToUpper(@this); }
  200. /// <summary>约束字符串用于 Key。</summary>
  201. public static string RestrictKey(this string @this) { return TextUtility.RestrictGuid(TextUtility.ToLower(@this)); }
  202. /// <summary>约束字符串长度范围,超出的部分将被截取去除。</summary>
  203. public static string RestrictLength(this string @this, int length) { return TextModifier.RestrictLength(@this, length); }
  204. /// <summary>约束字符串长度为 32,超出的部分将被截取去除。</summary>
  205. public static string Restrict32(this string @this) { return TextModifier.RestrictLength(@this, 32); }
  206. /// <summary>约束字符串长度为 255,超出的部分将被截取去除。</summary>
  207. public static string Restrict255(this string @this) { return TextModifier.RestrictLength(@this, 255); }
  208. /// <summary>约束字符串长度为 2000,超出的部分将被截取去除。</summary>
  209. public static string Restrict2000(this string @this) { return TextModifier.RestrictLength(@this, 2000); }
  210. /// <summary>追加字符串。</summary>
  211. public static string Append(this string @this, params object[] text) { return TextUtility.Merge(@this, TextUtility.Merge(text)); }
  212. /// <summary>追加文本。</summary>
  213. public static void Append(this StringBuilder @this, params object[] text) { TextUtility.Append(@this, text); }
  214. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  215. public static string AntiInject(this string @this, int length = -1, string blacklist = null) { return TextUtility.AntiInject(@this, length, blacklist); }
  216. /// <summary>将 Base64 字符串转换为字节数组。</summary>
  217. public static byte[] AntiBase64(this string @this) { return BinaryUtility.FromBase64(@this); }
  218. /// <summary>对 URL 编码。</summary>
  219. public static string EncodeUrl(this string @this) { return UrlEncoding.Encode(@this); }
  220. /// <summary>对 URL 解码。</summary>
  221. public static string DecodeUrl(this string @this) { return UrlEncoding.Decode(@this); }
  222. #endregion
  223. #region Byte[]
  224. /// <summary>将字节数组格式化为大写十六进制字符串。<para>例:D41D8CD98F00B204E9800998ECF8427E</para></summary>
  225. public static string ToX2(this byte[] @this) { return BinaryUtility.ToX2(@this); }
  226. /// <summary>克隆字节数组。当源为 NULL 时,将获取零元素字节数组。</summary>
  227. public static byte[] Clone(this byte[] @this) { return BinaryUtility.Clone(@this); }
  228. /// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
  229. public static bool StartsWith(this byte[] @this, params byte[] head) { return BinaryUtility.StartsWith(@this, head); }
  230. /// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
  231. public static bool EndsWith(this byte[] @this, params byte[] head) { return BinaryUtility.EndsWith(@this, head); }
  232. /// <summary>将字节数组转换为 Base64 字符串。</summary>
  233. public static string ToBase64(this byte[] @this) { return BinaryUtility.ToBase64(@this); }
  234. /// <summary>获取 MD5 值。</summary>
  235. public static byte[] GetMD5(params byte[] @this) { return BinaryUtility.MD5(@this); }
  236. /// <summary>获取 SHA1 值。</summary>
  237. public static byte[] GetSHA1(params byte[] @this) { return BinaryUtility.SHA1(@this); }
  238. #if !NET20
  239. /// <summary>获取 SHA256 值。</summary>
  240. public static byte[] GetSHA256(params byte[] @this) { return BinaryUtility.SHA256(@this); }
  241. #endif
  242. /// <summary>将字节数组转换为文本,默认为 UTF-8。</summary>
  243. public static string GetString(this byte[] @this, Encoding encoding = null) { return TextUtility.FromBinary(@this, encoding); }
  244. /// <summary>将字节数组转换为文本,默认为 UTF-8。</summary>
  245. public static string ToText(this byte[] @this, Encoding encoding = null) { return TextUtility.FromBinary(@this, encoding); }
  246. /// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
  247. public static byte[] AddTextBom(this byte[] @this) { return BinaryUtility.AddTextBom(@this); }
  248. /// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
  249. public static byte[] WipeTextBom(this byte[] @this) { return BinaryUtility.WipeTextBom(@this); }
  250. /// <summary>为字节数组增加字节。</summary>
  251. public static byte[] Append(this byte[] @this, params byte[] bytes) { return BinaryUtility.Append(@this, bytes); }
  252. /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
  253. /// <param name="bytes">要检查的字节数组。</param>
  254. /// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
  255. public static bool IsUTF8(this byte[] @this, int checkLength = 1048576) { return BinaryUtility.IsUTF8(@this, checkLength, null); }
  256. /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
  257. public static bool ContainsBOM(this byte[] @this) { return BinaryUtility.ContainsBOM(@this); }
  258. #endregion
  259. #region DateTime
  260. /// <summary>获取毫秒时间戳。</summary>
  261. public static long GetStamp(this DateTime @this)
  262. {
  263. return DateTimeUtility.GetStamp(@this);
  264. }
  265. /// <summary>获取毫秒时间戳。</summary>
  266. public static long ToStamp(this DateTime @this)
  267. {
  268. return DateTimeUtility.ToStamp(@this);
  269. }
  270. /// <summary>转换为易于阅读的文本。</summary>
  271. public static string ToLucid(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true)
  272. {
  273. return DateTimeUtility.ToLucid(@this, date, time, seconds, milliseconds);
  274. }
  275. /// <summary>转换为紧凑的文本。</summary>
  276. public static string ToCompact(this DateTime @this, bool date = true, bool time = true, bool seconds = true, bool milliseconds = true)
  277. {
  278. return DateTimeUtility.ToCompact(@this, date, time, seconds, milliseconds);
  279. }
  280. /// <summary>当前 DateTime 为闰年。</summary>
  281. public static bool IsLeapYear(this DateTime @this)
  282. {
  283. return DateTimeUtility.IsLeapYear(DateTimeUtility.GetDateTime(@this).Year);
  284. }
  285. #endregion
  286. #region Json
  287. /// <summary>生成 JSON 对象,失败时返回 NULL。</summary>
  288. /// <param name="this">将要解析的对象。</param>
  289. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  290. /// <param name="depth">解析深度。</param>
  291. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  292. public static Json ToJson(this IDictionary @this, bool lowerCase = false, int depth = -1, bool force = false)
  293. {
  294. return Json.Parse(@this, lowerCase, depth, force);
  295. }
  296. /// <summary>解析实现 IList 的对象为 Json 对象,失败时返回 Null。</summary>
  297. /// <param name="this">将要解析的对象。</param>
  298. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  299. /// <param name="depth">解析深度。</param>
  300. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  301. public static Json ToJson(this IList @this, bool lowerCase = false, int depth = -1, bool force = false)
  302. {
  303. return Json.Parse(@this, lowerCase, depth, force);
  304. }
  305. /// <summary>
  306. /// <para>解析对象为 Json 对象,包含所有公共属性,失败时返回 Null。</para>
  307. /// <para>String 对象将解析文本;Json 对象将返回实例;String 对象将解析文本;实现 IDictionary 或 IList 的对象将解析内容。</para>
  308. /// </summary>
  309. /// <param name="this">将要解析的对象。</param>
  310. /// <param name="lowerCase">在 Json 中将属性名称转换为小写。</param>
  311. /// <param name="depth">解析深度。</param>
  312. /// <param name="force">强制解析所有属性,忽略 Serializable 特性。</param>
  313. /// <exception cref="System.Exception"></exception>
  314. public static Json ToJson(object @this, bool lowerCase = false, int depth = -1, bool force = false)
  315. {
  316. return Json.Parse(@this, lowerCase, depth, force);
  317. }
  318. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  319. /// <param name="this">将要解析的对象。</param>
  320. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  321. /// <param name="ignoreCharacters">忽略的属性名称字符。</param>
  322. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  323. public static T FillObject<T>(this Json @this, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) where T : class, new()
  324. {
  325. return Json.FillObject<T>(@this, ignoreCase, ignoreCharacters, force);
  326. }
  327. /// <summary>填充类型实例,失败时返回 NULL 值。</summary>
  328. /// <param name="this">将要解析的对象。</param>
  329. /// <param name="ignoreCase">忽略属性名称大小写。</param>
  330. /// <param name="ignoreCharacters">忽略的属性名称字符。</param>
  331. /// <param name="force">强制填充,忽略 <typeparamref name="T"/> 的 Serializable 特性。</param>
  332. public static List<T> FillArray<T>(this Json @this, bool ignoreCase = true, string ignoreCharacters = null, bool force = false) where T : class, new()
  333. {
  334. return Json.FillArray<T>(@this, ignoreCase, ignoreCharacters, force);
  335. }
  336. /// <summary>设置属性名称为小写。</summary>
  337. public static Json ToLower(this Json @this)
  338. {
  339. return Json.ToLower(@this);
  340. }
  341. #endregion
  342. #region Stream
  343. /// <summary>重置流的位置到开始位置。</summary>
  344. public static bool ResetPosition(this Stream @this)
  345. {
  346. return StreamHelper.ResetPosition(@this);
  347. }
  348. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的字节数。</summary>
  349. public static long Read(this Stream @this, Stream destination, Action<long> progress = null)
  350. {
  351. return BinaryUtility.Read(@this, destination, progress);
  352. }
  353. /// <summary>读取源流中的数据,获取写入的字节。</summary>
  354. public static byte[] Read(this Stream @this, bool dispose = false)
  355. {
  356. return BinaryUtility.Read(@this, dispose);
  357. }
  358. /// <summary>向流写入数据。</summary>
  359. /// <param name="this">源流。</param>
  360. /// <param name="bytes">要写入的数据。</param>
  361. public static long Write(this Stream @this, params byte[] bytes)
  362. {
  363. return BinaryUtility.Write(@this, bytes);
  364. }
  365. /// <summary>读取源流中的数据,并将数据写入当前流,获取写入的字节数。</summary>
  366. /// <param name="this">目标流。</param>
  367. /// <param name="source">源流。</param>
  368. public static long Write(this Stream @this, Stream source)
  369. {
  370. return StreamHelper.Read(source, @this);
  371. }
  372. /// <summary>获取 MD5 值。</summary>
  373. public static byte[] MD5(this Stream @this)
  374. {
  375. return BinaryUtility.MD5(@this);
  376. }
  377. /// <summary>获取 SHA1 值。</summary>
  378. public static byte[] SHA1(this Stream @this)
  379. {
  380. return BinaryUtility.SHA1(@this);
  381. }
  382. #if !NET20
  383. /// <summary>获取 SHA256 值。</summary>
  384. public static byte[] SHA256(this Stream @this)
  385. {
  386. return BinaryUtility.SHA256(@this);
  387. }
  388. #endif
  389. #endregion
  390. #region Type
  391. /// <summary>判断指定类型具有特性。</summary>
  392. public static bool ContainsAttribute<T>(this Type @this, bool inherit = false) where T : Attribute
  393. {
  394. return ClassUtility.ContainsAttribute<T>(@this, inherit);
  395. }
  396. #endregion
  397. #region IEnumerable、Array、List、Dictionary
  398. /// <summary></summary>
  399. /// <exception cref="ArgumentNullException"></exception>
  400. public static void Add<T>(this IList<T> @this, params T[] items)
  401. {
  402. if (@this == null) throw new ArgumentNullException();
  403. foreach (var item in items) @this.Add(item);
  404. }
  405. /// <summary></summary>
  406. /// <exception cref="ArgumentNullException"></exception>
  407. public static void Add<T>(this IList<T> @this, IEnumerable<T> items)
  408. {
  409. if (@this == null) throw new ArgumentNullException();
  410. foreach (var item in items) @this.Add(item);
  411. }
  412. /// <summary></summary>
  413. public static bool IsEmpty<T>(this IEnumerable<T> @this) { return ClassUtility.IsEmpty(@this); }
  414. /// <summary></summary>
  415. public static bool NotEmpty<T>(this IEnumerable<T> @this) { return ClassUtility.NotEmpty(@this); }
  416. /// <summary></summary>
  417. public static bool Contains<T>(this IEnumerable<T> @this, T cell) { return ClassUtility.Contains<T>(@this, cell); }
  418. /// <summary></summary>
  419. public static List<T> Sub<T>(this IEnumerable<T> @this, long start = 0, long count = -1, Func<T> stuffer = null) { return ClassUtility.Sub<T>(@this, start, count, stuffer); }
  420. /// <summary>安全转换为 List&lt;<typeparamref name="T"/>&gt; 对象。可指定排除 NULL 值元素。</summary>
  421. /// <typeparam name="T"></typeparam>
  422. public static List<T> SafeList<T>(this IEnumerable<T> @this, bool excludeNull = false) { return ClassUtility.ToList<T>(@this, excludeNull); }
  423. /// <summary>升序排序。</summary>
  424. public static List<T> SortAscend<T>(this List<T> @this) where T : IComparable<T>
  425. {
  426. return SortUtility.AscendT(@this);
  427. }
  428. /// <summary>降序排序。</summary>
  429. public static List<T> SortDescend<T>(this List<T> @this) where T : IComparable<T>
  430. {
  431. return SortUtility.DescendT<T>(@this);
  432. }
  433. /// <summary>对 Key 排序。</summary>
  434. public static Dictionary<string, string> SortKey(this Dictionary<string, string> @this, bool ascend = true)
  435. {
  436. return SortHelper.DictionaryStringString(@this, true, ascend);
  437. }
  438. /// <summary>对 Value 排序。</summary>
  439. public static Dictionary<string, string> SortValue(this Dictionary<string, string> @this, bool ascend = true)
  440. {
  441. return SortHelper.DictionaryStringString(@this, false, ascend);
  442. }
  443. /// <summary>对 Key 排序。</summary>
  444. public static Dictionary<string, double> SortKey(this Dictionary<string, double> @this, bool ascend = true)
  445. {
  446. return SortHelper.DictionaryStringDouble(@this, true, ascend);
  447. }
  448. /// <summary>对 Value 排序。</summary>
  449. public static Dictionary<string, double> SortValue(this Dictionary<string, double> @this, bool ascend = true)
  450. {
  451. return SortHelper.DictionaryStringDouble(@this, false, ascend);
  452. }
  453. /// <summary>获取列表中的第一个 Item 对象。可指定失败时的默认返回值。</summary>
  454. public static T SafeFirst<T>(this IList<T> @this, T failed = default(T))
  455. {
  456. if (@this == null) return failed;
  457. if (@this.Count < 1) return failed;
  458. return @this[0];
  459. }
  460. /// <summary>添加元素。</summary>
  461. /// <typeparam name="TKey"></typeparam>
  462. /// <typeparam name="TValue"></typeparam>
  463. /// <param name="this"></param>
  464. /// <param name="key"></param>
  465. /// <param name="value"></param>
  466. public static bool Add<TKey, TValue>(this IList<KeyValuePair<TKey, TValue>> @this, TKey key, TValue value)
  467. {
  468. if (@this == null) return false;
  469. @this.Add(new KeyValuePair<TKey, TValue>(key, value));
  470. return true;
  471. }
  472. #endregion
  473. #region Source
  474. /// <summary>为记录的 Key 属性设置新值。</summary>
  475. public static void SetNewKey(this Record @this)
  476. {
  477. if (@this != null) @this.Key = Record.GenerateKey();
  478. }
  479. /// <summary>修补基本属性。</summary>
  480. public static void FixProperties(this Record @this)
  481. {
  482. Record.FixProperties(@this);
  483. }
  484. /// <summary></summary>
  485. public static DateTime DateTime(this IQuery @this, int row, string column)
  486. {
  487. if (@this == null) return DateTimeUtility.Origin;
  488. var value = @this.Value(row, column);
  489. if (value == null) return DateTimeUtility.Origin;
  490. if (value is DateTime) return (DateTime)value;
  491. DateTime result;
  492. var parsed = System.DateTime.TryParse(value.ToString(), out result);
  493. return parsed ? result : DateTimeUtility.Origin;
  494. }
  495. /// <summary></summary>
  496. public static Int32 Int32(this IQuery @this, int row, string column)
  497. {
  498. if (@this == null) return 0;
  499. return ToInt32(@this.Text(row, column));
  500. }
  501. /// <summary></summary>
  502. public static Int64 Int64(this IQuery @this, int row, string column)
  503. {
  504. if (@this == null) return 0L;
  505. return ToInt64(@this.Text(row, column));
  506. }
  507. /// <summary></summary>
  508. public static Decimal Decimal(this IQuery @this, int row, string column)
  509. {
  510. if (@this == null) return 0M;
  511. return ToDecimal(@this.Text(row, column));
  512. }
  513. /// <summary></summary>
  514. public static Double Double(this IQuery @this, int row, string column)
  515. {
  516. if (@this == null) return 0d;
  517. return ToDouble(@this.Text(row, column));
  518. }
  519. #endregion
  520. #region Web API
  521. #if NETFX
  522. /// <summary>获取查询字符串。</summary>
  523. public static string QueryString(this ApiRequest @this, string name, bool decode = false)
  524. {
  525. return PageUtility.QueryString(name, decode);
  526. }
  527. /// <summary>获取表单。</summary>
  528. public static string Form(this ApiRequest @this, string name)
  529. {
  530. return PageUtility.RequestForm(name);
  531. }
  532. /// <summary>获取 URL 查询段,不存在的段为 NULL 值。可要求解码。</summary>
  533. public static string GetSegmental(this Uri @this, int index = 3, bool decode = false)
  534. {
  535. return WebUtility.GetSegmental(@this, index, decode);
  536. }
  537. /// <summary>获取 URL 查询段,不存在的段为 NULL 值。可要求解码。</summary>
  538. public static string GetSegmentalUrl(this ApiRequest @this, int index = 3, bool decode = false)
  539. {
  540. return WebUtility.GetSegmentalUrl(@this, index, decode);
  541. }
  542. /// <summary>获取参数,指定可能的参数名,从 URL 中获取参数时将解码。</summary>
  543. public static string GetParameter(this ApiRequest @this, params string[] names)
  544. {
  545. return WebUtility.GetParameter(@this, names);
  546. }
  547. #endif
  548. #if NETFX || NETCORE
  549. /// <summary>设置 status 为 error,并设置 message 的内容。</summary>
  550. public static void Error(this ApiResponse @this, string message = "未知错误。")
  551. {
  552. ApiInternals.RespondError(@this, message);
  553. }
  554. /// <summary>设置 status 为 error,并设置 message 的内容。</summary>
  555. public static void Error(this ApiResponse @this, Exception exception)
  556. {
  557. ApiInternals.RespondError(@this, exception);
  558. }
  559. /// <summary>输出 UTF-8 文本。</summary>
  560. public static void Text(this ApiResponse @this, string content, string type = "text/plain")
  561. {
  562. ApiInternals.RespondText(@this, content, type);
  563. }
  564. /// <summary>输出字节数组。</summary>
  565. public static void Binary(this ApiResponse @this, byte[] content, string type = "application/octet-stream")
  566. {
  567. ApiInternals.RespondBinary(@this, content, type);
  568. }
  569. /// <summary>输出二进制。</summary>
  570. public static void Binary(this ApiResponse @this, Stream content, string type = "application/octet-stream")
  571. {
  572. ApiInternals.RespondBinary(@this, content, type);
  573. }
  574. /// <summary>输出文件。</summary>
  575. public static void File(this ApiResponse @this, Stream stream, string name, string type = "application/octet-stream")
  576. {
  577. ApiInternals.RespondFile(@this, stream, name, type);
  578. }
  579. /// <summary>重定向。</summary>
  580. public static void Redirect(this ApiResponse @this, string url)
  581. {
  582. ApiInternals.RespondRedirect(@this, url);
  583. }
  584. /// <summary></summary>
  585. /// <typeparam name="T"></typeparam>
  586. /// <param name="this"></param>
  587. /// <returns></returns>
  588. public static T Use<T>(this ApiController @this) where T : ApiController, new()
  589. {
  590. var current = @this;
  591. var target = new T();
  592. if (current != null)
  593. {
  594. target.Request = current.Request;
  595. target.Response = current.Response;
  596. target.AfterInitialized?.Invoke();
  597. }
  598. return target;
  599. }
  600. /// <summary></summary>
  601. /// <param name="this"></param>
  602. /// <param name="list"></param>
  603. /// <param name="lower"></param>
  604. /// <param name="depth"></param>
  605. /// <param name="force"></param>
  606. public static void Respond(this ApiResponse @this, IList list, bool lower = true, int depth = -1, bool force = false)
  607. {
  608. if (@this == null) return;
  609. if (list == null)
  610. {
  611. @this.Error("获取失败。");
  612. return;
  613. }
  614. @this.Data.SetProperty("count", list.Count);
  615. @this.Data.SetProperty("list", Json.Parse(list, lower, depth, force));
  616. }
  617. /// <summary></summary>
  618. /// <param name="this"></param>
  619. /// <param name="record"></param>
  620. /// <param name="lower"></param>
  621. public static void Respond(this ApiResponse @this, Record record, bool lower = true)
  622. {
  623. if (@this == null) return;
  624. if (record == null)
  625. {
  626. @this.Error("获取失败。");
  627. return;
  628. }
  629. @this.Data.Reset(Json.Parse(record, lower));
  630. }
  631. #endif
  632. #endregion
  633. #region Surface
  634. #if NETFX || NETCORE
  635. /// <summary></summary>
  636. public static void Invoke(this Control @this, Action action, bool async = false)
  637. {
  638. FormsUtility.Invoke(@this, action, async);
  639. }
  640. #endif
  641. #endregion
  642. }