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.

1104 lines
39 KiB

3 years ago
12 months ago
4 years ago
3 years ago
3 years ago
7 months ago
3 years ago
7 months 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
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
3 years ago
2 years ago
12 months ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
12 months 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
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
2 years ago
4 years ago
4 years ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 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
  1. using Apewer.Internals;
  2. using Apewer.Models;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Reflection;
  9. using System.Runtime.CompilerServices;
  10. using System.Text;
  11. using System.Threading;
  12. using static System.Net.Mime.MediaTypeNames;
  13. namespace Apewer
  14. {
  15. /// <summary>运行时实用工具。</summary>
  16. public static class RuntimeUtility
  17. {
  18. /// <summary>使用默认比较器判断相等。</summary>
  19. public static bool Equals<T>(T a, T b) => EqualityComparer<T>.Default.Equals(a, b);
  20. #region 反射操作
  21. /// <summary>从外部加载对象。</summary>
  22. public static object CreateObject(string path, string type, bool ignoreCase)
  23. {
  24. try
  25. {
  26. var a = Assembly.LoadFrom(path);
  27. var t = a.GetType(type, false, ignoreCase);
  28. if (t != null)
  29. {
  30. var result = Activator.CreateInstance(t);
  31. return result;
  32. }
  33. }
  34. catch { }
  35. return null;
  36. }
  37. /// <summary>对每个属性执行动作。</summary>
  38. public static void ForEachProperties(object instance, Action<Property> action, bool withNonPublic = true, bool withStatic = false)
  39. {
  40. if (instance == null || action == null) return;
  41. var type = instance.GetType();
  42. if (type == null) return;
  43. var properties = new List<PropertyInfo>();
  44. properties.AddRange(type.GetProperties());
  45. if (withNonPublic) properties.AddRange(type.GetProperties(BindingFlags.NonPublic));
  46. foreach (var info in properties)
  47. {
  48. var arg = new Property()
  49. {
  50. Instance = instance,
  51. Type = type,
  52. Information = info,
  53. Getter = info.GetGetMethod(),
  54. Setter = info.GetSetMethod()
  55. };
  56. if (arg.IsStatic && !withStatic) continue;
  57. action.Invoke(arg);
  58. }
  59. }
  60. #endregion
  61. #region Type
  62. /// <summary>判断指定类型可序列化。</summary>
  63. public static bool CanSerialize(Type type, bool inherit = false)
  64. {
  65. if (type == null) return false;
  66. var nsas = type.GetCustomAttributes(typeof(NonSerializedAttribute), inherit);
  67. if (nsas != null && nsas.Length > 0) return false;
  68. var sas = type.GetCustomAttributes(typeof(SerializableAttribute), inherit);
  69. if (sas != null && sas.Length > 0) return true;
  70. var tas = type.GetCustomAttributes(typeof(Source.TableAttribute), inherit);
  71. if (tas != null && tas.Length > 0) return true;
  72. return false;
  73. }
  74. /// <summary>获取类型的完整名称。</summary>
  75. public static string FullName(Type type)
  76. {
  77. if (type == null) return null;
  78. var sb = new StringBuilder();
  79. var ns = type.Namespace;
  80. if (!string.IsNullOrEmpty(ns))
  81. {
  82. sb.Append(ns);
  83. sb.Append(".");
  84. }
  85. var name = type.Name;
  86. var g = name.IndexOf('`');
  87. if (g > -1) name = name.Substring(0, g);
  88. sb.Append(name);
  89. var gts = type.GetGenericArguments();
  90. if (gts != null && gts.Length > 0)
  91. {
  92. var ts = new List<string>(gts.Length);
  93. foreach (var gt in gts) ts.Add(FullName(gt));
  94. sb.Append("<");
  95. sb.Append(string.Join(",", ts.ToArray()));
  96. sb.Append(">");
  97. }
  98. return sb.ToString();
  99. }
  100. /// <summary>检查类型。</summary>
  101. public static bool TypeEquals(object instance, Type type)
  102. {
  103. if (instance == null) return type == null ? true : false;
  104. if (instance is PropertyInfo)
  105. {
  106. return ((PropertyInfo)instance).PropertyType.Equals(type);
  107. }
  108. if (instance is MethodInfo)
  109. {
  110. return ((MethodInfo)instance).ReturnType.Equals(type);
  111. }
  112. return instance.GetType().Equals(type);
  113. }
  114. /// <summary>检查类型。</summary>
  115. public static bool TypeEquals<T>(object instance) => TypeEquals(instance, typeof(T));
  116. /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
  117. public static T GetAttribute<T>(object target) where T : Attribute
  118. {
  119. if (target == null) return null;
  120. try { return GetAttribute<T>(target.GetType()); } catch { return null; }
  121. }
  122. /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
  123. public static T GetAttribute<T>(Type target, bool inherit = false) where T : Attribute
  124. {
  125. if (target == null) return null;
  126. try
  127. {
  128. var type = target;
  129. var attributes = type.GetCustomAttributes(typeof(T), inherit);
  130. if (attributes.LongLength > 0L)
  131. {
  132. var attribute = attributes[0] as T;
  133. return attribute;
  134. }
  135. }
  136. catch { }
  137. return null;
  138. }
  139. /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
  140. public static T GetAttribute<T>(PropertyInfo property, bool inherit = false) where T : Attribute
  141. {
  142. if (property == null) return null;
  143. try
  144. {
  145. var type = property;
  146. var attributes = type.GetCustomAttributes(typeof(T), inherit);
  147. if (attributes.LongLength > 0L)
  148. {
  149. var attribute = attributes[0] as T;
  150. return attribute;
  151. }
  152. }
  153. catch { }
  154. return null;
  155. }
  156. /// <summary>获取指定的首个特性,特性不存在时返回 Null 值。</summary>
  157. public static T GetAttribute<T>(MethodInfo methods, bool inherit = false) where T : Attribute
  158. {
  159. if (methods == null) return null;
  160. try
  161. {
  162. var type = methods;
  163. var attributes = type.GetCustomAttributes(typeof(T), inherit);
  164. if (attributes.LongLength > 0L)
  165. {
  166. var attribute = attributes[0] as T;
  167. return attribute;
  168. }
  169. }
  170. catch { }
  171. return null;
  172. }
  173. /// <summary>获取一个值,指示该属性是否 static。</summary>
  174. public static bool IsStatic(PropertyInfo property, bool withNonPublic = false)
  175. {
  176. if (property == null) return false;
  177. var getter = property.GetGetMethod();
  178. if (getter != null) return getter.IsStatic;
  179. if (withNonPublic)
  180. {
  181. getter = property.GetGetMethod(true);
  182. if (getter != null) return getter.IsStatic;
  183. }
  184. var setter = property.GetSetMethod();
  185. if (setter != null) return setter.IsStatic;
  186. if (withNonPublic)
  187. {
  188. setter = property.GetSetMethod(true);
  189. if (setter != null) return setter.IsStatic;
  190. }
  191. return false;
  192. }
  193. /// <summary>调用方法。</summary>
  194. /// <exception cref="ArgumentException"></exception>
  195. /// <exception cref="InvalidOperationException"></exception>
  196. /// <exception cref="MethodAccessException"></exception>
  197. /// <exception cref="NotSupportedException"></exception>
  198. /// <exception cref="TargetException"></exception>
  199. /// <exception cref="TargetInvocationException"></exception>
  200. /// <exception cref="TargetParameterCountException"></exception>
  201. public static object Invoke(this MethodInfo method, object instance, params object[] parameters)
  202. {
  203. if (instance == null || method == null) return null;
  204. var pis = method.GetParameters();
  205. if (pis == null || pis.Length < 1) return method.Invoke(instance, null);
  206. if (parameters == null) return method.Invoke(instance, null);
  207. return method.Invoke(instance, parameters);
  208. }
  209. /// <summary>调用泛型对象的 ToString() 方法。</summary>
  210. public static string ToString<T>(T target)
  211. {
  212. var type = typeof(T);
  213. var methods = type.GetMethods();
  214. foreach (var method in methods)
  215. {
  216. if (method.Name != "ToString") continue;
  217. if (method.GetParameters().LongLength > 0L) continue;
  218. var result = (string)method.Invoke(target, null);
  219. return result;
  220. }
  221. return null;
  222. }
  223. /// <summary>获取属性值。</summary>
  224. /// <exception cref="ArgumentException"></exception>
  225. /// <exception cref="InvalidOperationException"></exception>
  226. /// <exception cref="MethodAccessException"></exception>
  227. /// <exception cref="NotSupportedException"></exception>
  228. /// <exception cref="TargetException"></exception>
  229. /// <exception cref="TargetInvocationException"></exception>
  230. /// <exception cref="TargetParameterCountException"></exception>
  231. public static T InvokeGet<T>(object instance, PropertyInfo property)
  232. {
  233. if (instance == null || property == null || !property.CanRead) return default;
  234. #if NET20 || NET40 || NET461
  235. var getter = property.GetGetMethod();
  236. if (getter != null)
  237. {
  238. try
  239. {
  240. var value = getter.Invoke(instance, null);
  241. if (value != null)
  242. {
  243. return (T)value;
  244. }
  245. }
  246. catch { }
  247. }
  248. return default;
  249. #else
  250. var value = property.GetValue(instance);
  251. try { return (T)value; } catch { return default; }
  252. #endif
  253. }
  254. /// <summary>设置属性值。</summary>
  255. /// <exception cref="ArgumentException"></exception>
  256. /// <exception cref="InvalidOperationException"></exception>
  257. /// <exception cref="MethodAccessException"></exception>
  258. /// <exception cref="NotSupportedException"></exception>
  259. /// <exception cref="TargetException"></exception>
  260. /// <exception cref="TargetInvocationException"></exception>
  261. /// <exception cref="TargetParameterCountException"></exception>
  262. public static void InvokeSet<T>(object instance, PropertyInfo property, T value)
  263. {
  264. if (instance == null || property == null || !property.CanWrite) return;
  265. #if NET20 || NET40
  266. var setter = property.GetSetMethod();
  267. if (setter != null)
  268. {
  269. try
  270. {
  271. setter.Invoke(instance, new object[] { value });
  272. }
  273. catch { }
  274. }
  275. #else
  276. property.SetValue(instance, value);
  277. #endif
  278. }
  279. /// <summary>指示方法是否存在于指定类型中。</summary>
  280. public static bool ExistIn(MethodInfo method, Type type)
  281. {
  282. if (method == null) return false;
  283. if (type == null) return false;
  284. return type.Equals(method.DeclaringType.Equals(type));
  285. }
  286. /// <summary>指示方法是否存在于指定类型中。</summary>
  287. public static bool ExistIn<T>(MethodInfo method)
  288. {
  289. if (method == null) return false;
  290. var type = typeof(T);
  291. return type.Equals(method.DeclaringType.Equals(type));
  292. }
  293. /// <summary>判断指定类型具有特性。</summary>
  294. private static bool Contains<T>(object[] attributes) where T : Attribute
  295. {
  296. if (attributes == null) return false;
  297. if (attributes.Length < 1) return false;
  298. var type = typeof(T);
  299. foreach (var attribute in attributes)
  300. {
  301. if (type.Equals(attribute.GetType())) return true;
  302. }
  303. return false;
  304. }
  305. /// <summary>判断指定类型具有特性。</summary>
  306. public static bool Contains<T>(ICustomAttributeProvider model, bool inherit = false) where T : Attribute
  307. {
  308. if (model == null) return false;
  309. var attributes = model.GetCustomAttributes(inherit);
  310. return Contains<T>(attributes);
  311. }
  312. /// <summary>判断基类。</summary>
  313. public static bool IsInherits(Type child, Type @base)
  314. {
  315. // 检查参数。
  316. if (child == null || @base == null) return false;
  317. if (child == @base) return false;
  318. // 检查 interface 类型。
  319. if (@base.IsInterface) return @base.IsAssignableFrom(child);
  320. // 忽略 System.Object。
  321. var quantum = typeof(object);
  322. if (@base.Equals(quantum)) return true;
  323. if (child.Equals(quantum)) return false;
  324. // 循环判断基类。
  325. var current = child;
  326. while (true)
  327. {
  328. var parent = current.BaseType;
  329. if (parent == null) return false;
  330. if (parent.Equals(@base)) return true;
  331. if (parent.Equals(quantum)) break;
  332. current = parent;
  333. }
  334. return false;
  335. }
  336. /// <summary></summary>
  337. public static Type[] GetTypes(Assembly assembly, bool onlyExported = false)
  338. {
  339. if (assembly == null) return null;
  340. try
  341. {
  342. return onlyExported ? assembly.GetExportedTypes() : assembly.GetTypes();
  343. }
  344. catch { }
  345. return new Type[0];
  346. }
  347. /// <summary>能从外部创建对象实例。</summary>
  348. public static bool CanNew<T>() => CanNew(typeof(T));
  349. /// <summary>能从外部创建对象实例。</summary>
  350. public static bool CanNew(Type type)
  351. {
  352. if (type == null) return false;
  353. if (!type.IsClass && !type.IsValueType) return false;
  354. if (type.IsAbstract) return false;
  355. var constructors = type.GetConstructors();
  356. foreach (var i in constructors)
  357. {
  358. if (i.IsPublic)
  359. {
  360. var parameters = i.GetParameters();
  361. if (parameters.Length < 1)
  362. {
  363. return true;
  364. }
  365. }
  366. }
  367. return false;
  368. }
  369. /// <summary>获取指定类型的默认值。</summary>
  370. public static object Default(Type type)
  371. {
  372. if (type == null || !type.IsValueType) return null;
  373. return Activator.CreateInstance(type);
  374. }
  375. /// <summary>判断指定对象是否为默认值。</summary>
  376. public static bool IsDefault(object value)
  377. {
  378. if (value.IsNull()) return true;
  379. var type = value.GetType();
  380. if (type.IsValueType) return value.Equals(Activator.CreateInstance(type));
  381. return false;
  382. }
  383. /// <summary>在程序集中枚举派生类型,可自定义检查器。</summary>
  384. public static Type[] DerivedTypes(Type baseType, Assembly assembly, Func<Type, bool> checker)
  385. {
  386. if (baseType == null) return new Type[0];
  387. if (assembly == null) return new Type[0];
  388. var types = GetTypes(assembly);
  389. var list = new List<Type>(types.Length);
  390. foreach (var type in types)
  391. {
  392. if (!IsInherits(type, baseType)) continue;
  393. if (checker != null && !checker(type)) continue;
  394. list.Add(type);
  395. }
  396. return list.ToArray();
  397. }
  398. /// <summary>是匿名类型。</summary>
  399. /// <exception cref="ArgumentNullException"></exception>
  400. public static bool IsAnonymousType(Type type)
  401. {
  402. if (type == null) throw new ArgumentNullException(nameof(type));
  403. // 类型是由编译器生成。
  404. if (!Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)) return false;
  405. // 是泛型。
  406. if (!type.IsGenericType) return false;
  407. // 名称。
  408. if (!type.Name.StartsWith("<>") || !type.Name.Contains("AnonymousType")) return false;
  409. // 私有。
  410. if (type.IsPublic) return false;
  411. return true;
  412. }
  413. /// <summary>获取数组元素的类型。</summary>
  414. /// <remarks>参数必须是正确的数组类型。</remarks>
  415. /// <exception cref="ArgumentException"></exception>
  416. /// <exception cref="ArgumentNullException"></exception>
  417. public static Type GetTypeOfArrayItem(Type arrayType)
  418. {
  419. if (arrayType == null) throw new ArgumentNullException(nameof(arrayType));
  420. if (!arrayType.BaseType.Equals(typeof(Array))) throw new ArgumentException($"参数 {arrayType} 不是有效的数组类型。");
  421. var methods = arrayType.GetMethods();
  422. foreach (var method in methods)
  423. {
  424. if (method.Name.ToLower() != "set") continue;
  425. var parameters = method.GetParameters();
  426. if (parameters.Length != 2) continue;
  427. var length = parameters[0].ParameterType;
  428. if (!length.Equals(typeof(int))) continue;
  429. var item = parameters[1].ParameterType;
  430. return item;
  431. }
  432. throw new ArgumentException($"参数 {arrayType} 不是有效的数组类型。");
  433. }
  434. /// <summary>是 Nullable&lt;T&gt; 类型。</summary>
  435. public static bool IsNullableType(this Type type)
  436. {
  437. if (type.IsGenericType && !type.IsGenericTypeDefinition)
  438. {
  439. Type genericTypeDefinition = type.GetGenericTypeDefinition();
  440. if ((object)genericTypeDefinition == typeof(Nullable<>))
  441. {
  442. return true;
  443. }
  444. }
  445. return false;
  446. }
  447. /// <summary>是 Nullable&lt;T&gt; 类型。</summary>
  448. public static bool IsNullableType(this Type type, out Type genericType)
  449. {
  450. if (type.IsGenericType && !type.IsGenericTypeDefinition)
  451. {
  452. Type genericTypeDefinition = type.GetGenericTypeDefinition();
  453. if ((object)genericTypeDefinition == typeof(Nullable<>))
  454. {
  455. genericType = type.GetGenericArguments()[0];
  456. return true;
  457. }
  458. }
  459. genericType = null;
  460. return false;
  461. }
  462. /// <summary>获取 Nullable&lt;T&gt; 实例的值。</summary>
  463. public static object GetNullableValue(object nullable)
  464. {
  465. var type = typeof(Nullable<>);
  466. var property = type.GetProperty("Value");
  467. var getter = property.GetGetMethod();
  468. var value = getter.Invoke(nullable, null);
  469. return value;
  470. }
  471. #endregion
  472. #region Collect & Dispose
  473. /// <summary>控制系统垃圾回收器(一种自动回收未使用内存的服务)。强制对所有代进行即时垃圾回收。</summary>
  474. public static void Collect() => GC.Collect();
  475. /// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>
  476. /// <returns>可能出现的错误信息。</returns>
  477. public static void Dispose(object instance, bool flush = false)
  478. {
  479. if (instance == null) return;
  480. var stream = instance as Stream;
  481. if (stream != null)
  482. {
  483. if (flush)
  484. {
  485. try { stream.Flush(); } catch { }
  486. }
  487. try { stream.Close(); } catch { }
  488. }
  489. var disposable = instance as IDisposable;
  490. if (disposable != null)
  491. {
  492. try
  493. {
  494. disposable.Dispose();
  495. }
  496. catch { }
  497. }
  498. }
  499. /// <summary>执行与释放或重置非托管资源关联的应用程序定义的任务。</summary>
  500. /// <returns>可能出现的错误信息。</returns>
  501. public static void Dispose<T>(IEnumerable<T> objects, bool flush = false)
  502. {
  503. if (objects != null)
  504. {
  505. foreach (var i in objects) Dispose(i, flush);
  506. }
  507. }
  508. #endregion
  509. #region Thread
  510. /// <summary>停止线程。</summary>
  511. public static void Abort(Thread thread)
  512. {
  513. if (thread == null) return;
  514. try
  515. {
  516. if (thread.IsAlive) thread.Abort();
  517. }
  518. catch { }
  519. }
  520. /// <summary>阻塞当前线程,时长以毫秒为单位。</summary>
  521. public static void Sleep(int milliseconds)
  522. {
  523. if (milliseconds > 0) Thread.Sleep(milliseconds);
  524. }
  525. private static void Invoke(Action action, bool @try = false)
  526. {
  527. if (action == null) return;
  528. if (@try)
  529. {
  530. try { action.Invoke(); } catch { }
  531. }
  532. else { action.Invoke(); }
  533. }
  534. /// <summary>在后台线程中执行,指定 Try 将忽略 Action 抛出的异常。</summary>
  535. /// <param name="action">要执行的 Action。</param>
  536. /// <param name="try">忽略 Action 抛出的异常。</param>
  537. /// <remarks>对返回的 Thread 调用 Abort 可结束线程的执行。</remarks>
  538. [MethodImpl(MethodImplOptions.NoInlining)]
  539. public static Thread InBackground(Action action, bool @try = false)
  540. {
  541. if (action == null) return null;
  542. var thread = new Thread(delegate (object v)
  543. {
  544. Invoke(() => ((Action)v)(), @try);
  545. });
  546. thread.IsBackground = true;
  547. thread.Start(action);
  548. return thread;
  549. }
  550. /// <summary>在后台线程中执行,指定 Try 将忽略 Action 抛出的异常。</summary>
  551. /// <param name="delay">延迟的毫秒数。</param>
  552. /// <param name="action">要执行的 Action。</param>
  553. /// <param name="try">忽略 Action 抛出的异常。</param>
  554. /// <remarks>对返回的 Thread 调用 Abort 可结束线程的执行。</remarks>
  555. [MethodImpl(MethodImplOptions.NoInlining)]
  556. public static Thread InBackground(int delay, Action action, bool @try = false)
  557. {
  558. if (action == null) return null;
  559. var thread = new Thread(delegate (object v)
  560. {
  561. if (delay > 0) Thread.Sleep(delay);
  562. Invoke(() => ((Action)v)(), @try);
  563. });
  564. thread.IsBackground = true;
  565. thread.Start(action);
  566. return thread;
  567. }
  568. /// <summary>启动线程,在新线程中执行。</summary>
  569. /// <param name="action">要执行的 Action。</param>
  570. /// <param name="background">设置线程为后台线程。</param>
  571. /// <param name="try">忽略 Action 抛出的异常。</param>
  572. /// <remarks>对返回的 Thread 调用 Abort 可结束线程的执行。</remarks>
  573. public static Thread StartThread(Action action, bool background = false, bool @try = false)
  574. {
  575. if (action == null) return null;
  576. var thread = new Thread(new ThreadStart(() => Invoke(action, @try)));
  577. thread.IsBackground = background;
  578. thread.Start();
  579. return thread;
  580. }
  581. /// <summary>经过指定时间(以毫秒为单位)后,在新线程(后台)中执行。</summary>
  582. /// <param name="action">要执行的 Action。</param>
  583. /// <param name="delay">调用 Action 之前延迟的时间量(以毫秒为单位)。</param>
  584. /// <param name="try">忽略 Action 抛出的异常。</param>
  585. /// <remarks>对返回的 Timer 调用 Dispose 可终止计时器,阻止调用。</remarks>
  586. public static Timer Timeout(Action action, int delay, bool @try = false)
  587. {
  588. if (action == null) return null;
  589. return new Timer((x) => Invoke((Action)x, @try), action, delay > 0 ? delay : 0, -1);
  590. }
  591. /// <summary>尝试在主线程调用。</summary>
  592. /// <exception cref="ArgumentNullException" />
  593. /// <exception cref="InvalidOperationException" />
  594. public static void OnMainThread(Action action)
  595. {
  596. if (action == null) throw new ArgumentNullException(nameof(action));
  597. var context = SynchronizationContext.Current;
  598. if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。");
  599. context.Send(state => { action.Invoke(); }, null);
  600. }
  601. /// <summary>尝试在主线程调用。</summary>
  602. /// <exception cref="ArgumentNullException" />
  603. /// <exception cref="InvalidOperationException" />
  604. public static TResult OnMainThread<TResult>(Func<TResult> func)
  605. {
  606. if (func == null) throw new ArgumentNullException(nameof(func));
  607. var context = SynchronizationContext.Current;
  608. if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。");
  609. var result = default(TResult);
  610. context.Send(state => result = func.Invoke(), null);
  611. return result;
  612. }
  613. #endregion
  614. #region Assembly
  615. /// <summary>列出当前域中的程序集。</summary>
  616. public static Assembly[] ListLoadedAssemblies()
  617. {
  618. return AppDomain.CurrentDomain.GetAssemblies();
  619. }
  620. /// <summary>从指定的程序集加载资源。</summary>
  621. /// <param name="name">资源的名称。</param>
  622. /// <param name="assembly">程序集,为 NULL 值时指向 CallingAssembly。</param>
  623. /// <returns>该资源的流,发生错误时返回 NULL 值。</returns>
  624. /// <remarks>此方法不引发异常。</remarks>
  625. public static Stream OpenResource(string name, Assembly assembly = null)
  626. {
  627. var stream = null as Stream;
  628. try
  629. {
  630. var asm = assembly ?? Assembly.GetCallingAssembly();
  631. stream = asm.GetManifestResourceStream(name);
  632. }
  633. catch { }
  634. return null;
  635. }
  636. /// <summary>从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。</summary>
  637. /// <param name="name">资源的名称。</param>
  638. /// <param name="assembly">程序集,为 NULL 值时指向 CallingAssembly。</param>
  639. /// <returns>该资源的流,发生错误时返回 NULL 值。</returns>
  640. /// <remarks>此方法不引发异常。</remarks>
  641. public static MemoryStream GetResource(string name, Assembly assembly = null)
  642. {
  643. var res = OpenResource(name, assembly);
  644. if (res == null) return null;
  645. var memory = new MemoryStream();
  646. BytesUtility.Read(res, memory);
  647. res.Dispose();
  648. return memory;
  649. }
  650. #if NETFRAMEWORK
  651. /// <summary>将代码生成为程序集。</summary>
  652. public static Assembly Compile(string code, bool executable = false, bool inMemory = true)
  653. {
  654. using (var cdp = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("C#"))
  655. {
  656. var cp = new System.CodeDom.Compiler.CompilerParameters();
  657. cp.ReferencedAssemblies.Add(typeof(void).Assembly.Location);
  658. cp.GenerateExecutable = false;
  659. cp.GenerateInMemory = true;
  660. cp.TempFiles = new System.CodeDom.Compiler.TempFileCollection(System.IO.Path.GetTempPath());
  661. var cr = cdp.CompileAssemblyFromSource(cp, code);
  662. if (cr.Errors.Count > 0) throw new Exception(cr.Errors[0].ErrorText);
  663. var assembly = cr.CompiledAssembly;
  664. return assembly;
  665. }
  666. }
  667. #endif
  668. #endregion
  669. #region Application
  670. private static Class<string> _AppPath = null;
  671. private static Class<string> _DataPath = null;
  672. private static Class<bool> _InIIS = null;
  673. /// <summary>当前应用程序由 IIS 托管。</summary>
  674. private static bool InIIS()
  675. {
  676. if (_InIIS != null) return _InIIS.Value;
  677. var dll = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
  678. var path1 = StorageUtility.CombinePath(ApplicationPath, dll);
  679. if (!File.Exists(path1))
  680. {
  681. var path2 = StorageUtility.CombinePath(ApplicationPath, "bin", dll);
  682. if (File.Exists(path2))
  683. {
  684. _InIIS = new Class<bool>(true);
  685. return true;
  686. }
  687. }
  688. _InIIS = new Class<bool>(false);
  689. return false;
  690. }
  691. /// <summary>获取当前应用程序所在目录的路径。</summary>
  692. /// <remarks>
  693. /// <para>程序示例: D:\App</para>
  694. /// <para>网站示例: D:\Website</para>
  695. /// </remarks>
  696. public static string ApplicationPath
  697. {
  698. get
  699. {
  700. var temp = _AppPath;
  701. if (!temp)
  702. {
  703. // AppDomain.CurrentDomain.BaseDirectory
  704. // AppDomain.CurrentDomain.SetupInformation.ApplicationBase
  705. // return AppDomain.CurrentDomain.BaseDirectory;
  706. #if NETSTD
  707. var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
  708. #else
  709. var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
  710. #endif
  711. path = TextUtility.AssureEnds(path, "\\", false);
  712. path = TextUtility.AssureEnds(path, "/", false);
  713. temp = new Class<string>(path);
  714. _AppPath = temp;
  715. }
  716. return temp.Value;
  717. }
  718. }
  719. /// <summary>获取数据目录的路径。</summary>
  720. public static string DataPath
  721. {
  722. get
  723. {
  724. var temp = _DataPath;
  725. if (!temp)
  726. {
  727. var app = ApplicationPath;
  728. // 网站使用 App_Data 目录。
  729. var appData = Path.Combine(app, "app_data");
  730. if (Directory.Exists(appData))
  731. {
  732. temp = new Class<string>(appData);
  733. }
  734. else if (File.Exists(Path.Combine(app, "web.config")))
  735. {
  736. StorageUtility.AssureDirectory(appData);
  737. temp = new Class<string>(appData);
  738. }
  739. else
  740. {
  741. // 获取并创建 Data 目录。
  742. var data = Path.Combine(app, "data");
  743. if (StorageUtility.AssureDirectory(data)) temp = new Class<string>(data);
  744. else temp = new Class<string>(app);
  745. }
  746. _DataPath = temp;
  747. }
  748. return temp.Value;
  749. }
  750. }
  751. /// <summary>获取可执行文件的路径。</summary>
  752. /// <remarks>
  753. /// <para>调用: System.Windows.Forms.Application.ExecutablePath</para>
  754. /// <para>示例: c:\windows\system32\inetsrv\w3wp.exe</para>
  755. /// </remarks>
  756. public static string ExecutablePath
  757. {
  758. get
  759. {
  760. var entry = Assembly.GetEntryAssembly();
  761. if (entry == null) return null;
  762. var escapedCodeBase = entry.EscapedCodeBase;
  763. var uri = new Uri(escapedCodeBase);
  764. if (uri.Scheme == "file") return uri.LocalPath + uri.Fragment;
  765. return uri.ToString();
  766. }
  767. }
  768. /// <summary>
  769. /// <para>System.AppDomain.CurrentDomain.BaseDirectory</para>
  770. /// <para>D:\Website\</para>
  771. /// </summary>
  772. private static string CurrentDomainPath
  773. {
  774. get { return AppDomain.CurrentDomain.BaseDirectory; }
  775. }
  776. /// <summary>
  777. /// <para>System.IO.Directory.GetCurrentDirectory()</para>
  778. /// <para>c:\windows\system32\inetsrv</para>
  779. /// </summary>
  780. private static string CurrentDirectory
  781. {
  782. get { return Directory.GetCurrentDirectory(); } // System.Environment.CurrentDirectory
  783. }
  784. /// <summary>
  785. /// <para>System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName</para>
  786. /// <para>c:\windows\system32\inetsrv\w3wp.exe</para>
  787. /// </summary>
  788. private static string ProcessMainModule
  789. {
  790. get { return Process.GetCurrentProcess().MainModule.FileName; }
  791. }
  792. #endregion
  793. #region Evaluate
  794. /// <summary>评估 Action 的执行时间,单位为毫秒。</summary>
  795. public static long Evaluate(Action action)
  796. {
  797. if (action == null) return 0;
  798. var stopwatch = new Stopwatch();
  799. stopwatch.Start();
  800. action.Invoke();
  801. stopwatch.Stop();
  802. return stopwatch.ElapsedMilliseconds;
  803. }
  804. #endregion
  805. #region Console
  806. /// <summary>获取或设置控制台标题。</summary>
  807. public static string Title
  808. {
  809. get { try { return Console.Title; } catch { return null; } }
  810. set { try { Console.Title = value; } catch { } }
  811. }
  812. /// <summary>设置在控制台中按 CTRL + C 时的方法。</summary>
  813. public static void CtrlCancel(Func<bool> exit)
  814. {
  815. const string postfix = " - 按 CTRL + C 可安全退出";
  816. var title = Title ?? "";
  817. if (!title.EndsWith(postfix))
  818. {
  819. title = title + postfix;
  820. Title = title;
  821. }
  822. if (exit == null) return;
  823. try { Console.CancelKeyPress += (s, e) => e.Cancel = !exit(); } catch { }
  824. }
  825. /// <summary>调用所有公共类,创建构造函数。</summary>
  826. /// <param name="assembly">要搜索类的程序集,指定为 NULL 时将获取当前程序集。</param>
  827. /// <param name="catchException">
  828. /// <para>指定为 TRUE 时将使用 TRY 语句捕获异常;</para>
  829. /// <para>指定为 FLASE 时发生异常将可能中断执行,可用于调试。</para></param>
  830. public static void InvokePublicClass(Assembly assembly = null, bool catchException = false)
  831. {
  832. const string Title = "Invoing Public Class";
  833. RuntimeUtility.Title = Title;
  834. var before = DateTime.Now;
  835. Logger.Internals.Info(typeof(RuntimeUtility), "Started Invoke.");
  836. var types = GetTypes(assembly ?? Assembly.GetCallingAssembly());
  837. foreach (var type in types)
  838. {
  839. if (!type.IsClass) continue;
  840. if (!type.IsPublic) continue;
  841. if (!CanNew(type)) continue;
  842. Logger.Internals.Info(typeof(RuntimeUtility), "Invoke " + type.FullName);
  843. RuntimeUtility.Title = type.FullName;
  844. try
  845. {
  846. Activator.CreateInstance(type);
  847. }
  848. catch (Exception ex)
  849. {
  850. var ex2 = ex.InnerException ?? ex;
  851. Logger.Internals.Exception(ex2, typeof(RuntimeUtility));
  852. if (!catchException) throw ex2;
  853. }
  854. }
  855. RuntimeUtility.Title = Title;
  856. var after = DateTime.Now;
  857. var span = after - before;
  858. var milli = Convert.ToInt64(span.TotalMilliseconds);
  859. var duration = $"{milli / 1000D} 秒";
  860. var result = "Finished Invoke.\n\n";
  861. result += $" Duration: {duration}\n";
  862. result += $" Started: {before.Lucid()}\n";
  863. result += $" Ended: {after.Lucid()}\n";
  864. Logger.Internals.Info(typeof(RuntimeUtility), result);
  865. }
  866. #endregion
  867. #region System
  868. /// <summary>结束当前进程。</summary>
  869. public static void Exit()
  870. {
  871. Environment.Exit(0);
  872. Process.GetCurrentProcess().Kill();
  873. }
  874. /// <summary>当前操作系统是 Windows。</summary>
  875. public static bool IsWindows
  876. {
  877. #if NETFRAMEWORK
  878. get => Environment.OSVersion.Platform == PlatformID.Win32NT;
  879. #else
  880. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
  881. #endif
  882. }
  883. /// <summary>当前操作系统是 OS X 或 macOS。</summary>
  884. public static bool IsOSX
  885. {
  886. #if NETFRAMEWORK
  887. get => Environment.OSVersion.Platform == PlatformID.MacOSX;
  888. #else
  889. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX);
  890. #endif
  891. }
  892. /// <summary>当前操作系统是 Linux。</summary>
  893. public static bool IsLinux
  894. {
  895. #if NETFRAMEWORK
  896. get => Environment.OSVersion.Platform == PlatformID.Unix;
  897. #else
  898. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux);
  899. #endif
  900. }
  901. #if NETFRAMEWORK
  902. /// <summary>当前进程是以管理员身份运行。</summary>
  903. public static bool IsAdministratorRole()
  904. {
  905. var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
  906. var principal = new System.Security.Principal.WindowsPrincipal(identity);
  907. var result = principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
  908. return result;
  909. }
  910. #endif
  911. #endregion
  912. #region Exception
  913. /// <summary>读取调用堆栈。</summary>
  914. public static string[] StackTrace()
  915. {
  916. var trace = new StackTrace(true);
  917. var frames = trace.GetFrames();
  918. var ab = new ArrayBuilder<string>();
  919. foreach (var frame in frames)
  920. {
  921. // 滤除当前方法。
  922. var method = frame.GetMethod();
  923. if (method == null) continue;
  924. var type = method.DeclaringType;
  925. if (type == null) continue;
  926. var value = $"{method.DeclaringType.FullName}.{method.Name}";
  927. ab.Add(value);
  928. }
  929. return ab.Export();
  930. }
  931. internal static string Message(Exception ex)
  932. {
  933. if (ex == null) return null;
  934. try
  935. {
  936. var message = ex.Message;
  937. if (!string.IsNullOrEmpty(message)) return message;
  938. var typeName = ex.GetType().FullName;
  939. message = $"异常 <{typeName}> 包含空消息。";
  940. return message;
  941. }
  942. catch
  943. {
  944. var typeName = ex.GetType().FullName;
  945. return $"获取 <{typeName}> 的消息时再次发生了异常。";
  946. }
  947. }
  948. #endregion
  949. }
  950. }