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.

1120 lines
40 KiB

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