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.

1064 lines
38 KiB

4 years ago
3 years ago
1 year ago
4 years ago
3 years ago
3 years ago
11 months ago
3 years ago
11 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
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
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.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Reflection;
  8. using System.Runtime.CompilerServices;
  9. using System.Threading;
  10. using System.Collections;
  11. using System.Text;
  12. namespace Apewer
  13. {
  14. /// <summary>运行时实用工具。</summary>
  15. public static class RuntimeUtility
  16. {
  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 @object, bool flush = false)
  477. {
  478. if (@object == null) return;
  479. var stream = @object 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 = @object 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>启动线程,在新线程中执行。</summary>
  550. /// <param name="action">要执行的 Action。</param>
  551. /// <param name="background">设置线程为后台线程。</param>
  552. /// <param name="try">忽略 Action 抛出的异常。</param>
  553. /// <remarks>对返回的 Thread 调用 Abort 可结束线程的执行。</remarks>
  554. public static Thread StartThread(Action action, bool background = false, bool @try = false)
  555. {
  556. if (action == null) return null;
  557. var thread = new Thread(new ThreadStart(() => Invoke(action, @try)));
  558. thread.IsBackground = background;
  559. thread.Start();
  560. return thread;
  561. }
  562. /// <summary>经过指定时间(以毫秒为单位)后,在新线程(后台)中执行。</summary>
  563. /// <param name="action">要执行的 Action。</param>
  564. /// <param name="delay">调用 Action 之前延迟的时间量(以毫秒为单位)。</param>
  565. /// <param name="try">忽略 Action 抛出的异常。</param>
  566. /// <remarks>对返回的 Timer 调用 Dispose 可终止计时器,阻止调用。</remarks>
  567. public static Timer Timeout(Action action, int delay, bool @try = false)
  568. {
  569. if (action == null) return null;
  570. return new Timer((x) => Invoke((Action)x, @try), action, delay > 0 ? delay : 0, -1);
  571. }
  572. /// <summary>尝试在主线程调用。</summary>
  573. /// <exception cref="ArgumentNullException" />
  574. /// <exception cref="InvalidOperationException" />
  575. public static void OnMainThread(Action action)
  576. {
  577. if (action == null) throw new ArgumentNullException(nameof(action));
  578. var context = SynchronizationContext.Current;
  579. if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。");
  580. context.Send(state => { action.Invoke(); }, null);
  581. }
  582. /// <summary>尝试在主线程调用。</summary>
  583. /// <exception cref="ArgumentNullException" />
  584. /// <exception cref="InvalidOperationException" />
  585. public static TResult OnMainThread<TResult>(Func<TResult> func)
  586. {
  587. if (func == null) throw new ArgumentNullException(nameof(func));
  588. var context = SynchronizationContext.Current;
  589. if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。");
  590. var result = default(TResult);
  591. context.Send(state => result = func.Invoke(), null);
  592. return result;
  593. }
  594. #endregion
  595. #region Assembly
  596. /// <summary>列出当前域中的程序集。</summary>
  597. public static Assembly[] ListLoadedAssemblies()
  598. {
  599. return AppDomain.CurrentDomain.GetAssemblies();
  600. }
  601. /// <summary>从指定的程序集加载资源。</summary>
  602. /// <param name="name">资源的名称。</param>
  603. /// <param name="assembly">程序集,为 NULL 值时指向 CallingAssembly。</param>
  604. /// <returns>该资源的流,发生错误时返回 NULL 值。</returns>
  605. /// <remarks>此方法不引发异常。</remarks>
  606. public static Stream OpenResource(string name, Assembly assembly = null)
  607. {
  608. var stream = null as Stream;
  609. try
  610. {
  611. var asm = assembly ?? Assembly.GetCallingAssembly();
  612. stream = asm.GetManifestResourceStream(name);
  613. }
  614. catch { }
  615. return null;
  616. }
  617. /// <summary>从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。</summary>
  618. /// <param name="name">资源的名称。</param>
  619. /// <param name="assembly">程序集,为 NULL 值时指向 CallingAssembly。</param>
  620. /// <returns>该资源的流,发生错误时返回 NULL 值。</returns>
  621. /// <remarks>此方法不引发异常。</remarks>
  622. public static MemoryStream GetResource(string name, Assembly assembly = null)
  623. {
  624. var res = OpenResource(name, assembly);
  625. if (res == null) return null;
  626. var memory = new MemoryStream();
  627. BytesUtility.Read(res, memory);
  628. res.Dispose();
  629. return memory;
  630. }
  631. #if NETFRAMEWORK
  632. /// <summary>将代码生成为程序集。</summary>
  633. public static Assembly Compile(string code, bool executable = false, bool inMemory = true)
  634. {
  635. using (var cdp = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("C#"))
  636. {
  637. var cp = new System.CodeDom.Compiler.CompilerParameters();
  638. cp.ReferencedAssemblies.Add(typeof(void).Assembly.Location);
  639. cp.GenerateExecutable = false;
  640. cp.GenerateInMemory = true;
  641. cp.TempFiles = new System.CodeDom.Compiler.TempFileCollection(System.IO.Path.GetTempPath());
  642. var cr = cdp.CompileAssemblyFromSource(cp, code);
  643. if (cr.Errors.Count > 0) throw new Exception(cr.Errors[0].ErrorText);
  644. var assembly = cr.CompiledAssembly;
  645. return assembly;
  646. }
  647. }
  648. #endif
  649. #endregion
  650. #region Application
  651. private static Class<string> _AppPath = null;
  652. private static Class<string> _DataPath = null;
  653. private static Class<bool> _InIIS = null;
  654. /// <summary>当前应用程序由 IIS 托管。</summary>
  655. private static bool InIIS()
  656. {
  657. if (_InIIS != null) return _InIIS.Value;
  658. var dll = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
  659. var path1 = StorageUtility.CombinePath(ApplicationPath, dll);
  660. if (!File.Exists(path1))
  661. {
  662. var path2 = StorageUtility.CombinePath(ApplicationPath, "bin", dll);
  663. if (File.Exists(path2))
  664. {
  665. _InIIS = new Class<bool>(true);
  666. return true;
  667. }
  668. }
  669. _InIIS = new Class<bool>(false);
  670. return false;
  671. }
  672. /// <summary>获取当前应用程序所在目录的路径。</summary>
  673. /// <remarks>
  674. /// <para>程序示例: D:\App</para>
  675. /// <para>网站示例: D:\Website</para>
  676. /// </remarks>
  677. public static string ApplicationPath
  678. {
  679. get
  680. {
  681. var temp = _AppPath;
  682. if (!temp)
  683. {
  684. // AppDomain.CurrentDomain.BaseDirectory
  685. // AppDomain.CurrentDomain.SetupInformation.ApplicationBase
  686. // return AppDomain.CurrentDomain.BaseDirectory;
  687. #if NETSTD
  688. var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
  689. #else
  690. var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
  691. #endif
  692. temp = new Class<string>(path);
  693. _AppPath = temp;
  694. }
  695. return temp.Value;
  696. }
  697. }
  698. /// <summary>获取数据目录的路径。</summary>
  699. public static string DataPath
  700. {
  701. get
  702. {
  703. var temp = _DataPath;
  704. if (!temp)
  705. {
  706. var app = ApplicationPath;
  707. // 网站使用 App_Data 目录。
  708. var appData = Path.Combine(app, "app_data");
  709. if (Directory.Exists(appData))
  710. {
  711. temp = new Class<string>(appData);
  712. }
  713. else if (File.Exists(Path.Combine(app, "web.config")))
  714. {
  715. StorageUtility.AssureDirectory(appData);
  716. temp = new Class<string>(appData);
  717. }
  718. else
  719. {
  720. // 获取并创建 Data 目录。
  721. var data = Path.Combine(app, "data");
  722. if (StorageUtility.AssureDirectory(data)) temp = new Class<string>(data);
  723. else temp = new Class<string>(app);
  724. }
  725. _DataPath = temp;
  726. }
  727. return temp.Value;
  728. }
  729. }
  730. /// <summary>获取可执行文件的路径。</summary>
  731. /// <remarks>
  732. /// <para>调用: System.Windows.Forms.Application.ExecutablePath</para>
  733. /// <para>示例: c:\windows\system32\inetsrv\w3wp.exe</para>
  734. /// </remarks>
  735. public static string ExecutablePath
  736. {
  737. get
  738. {
  739. var entry = Assembly.GetEntryAssembly();
  740. if (entry == null) return null;
  741. var escapedCodeBase = entry.EscapedCodeBase;
  742. var uri = new Uri(escapedCodeBase);
  743. if (uri.Scheme == "file") return uri.LocalPath + uri.Fragment;
  744. return uri.ToString();
  745. }
  746. }
  747. /// <summary>
  748. /// <para>System.AppDomain.CurrentDomain.BaseDirectory</para>
  749. /// <para>D:\Website\</para>
  750. /// </summary>
  751. private static string CurrentDomainPath
  752. {
  753. get { return AppDomain.CurrentDomain.BaseDirectory; }
  754. }
  755. /// <summary>
  756. /// <para>System.IO.Directory.GetCurrentDirectory()</para>
  757. /// <para>c:\windows\system32\inetsrv</para>
  758. /// </summary>
  759. private static string CurrentDirectory
  760. {
  761. get { return Directory.GetCurrentDirectory(); } // System.Environment.CurrentDirectory
  762. }
  763. /// <summary>
  764. /// <para>System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName</para>
  765. /// <para>c:\windows\system32\inetsrv\w3wp.exe</para>
  766. /// </summary>
  767. private static string ProcessMainModule
  768. {
  769. get { return Process.GetCurrentProcess().MainModule.FileName; }
  770. }
  771. #endregion
  772. #region Evaluate
  773. /// <summary>评估 Action 的执行时间,单位为毫秒。</summary>
  774. public static long Evaluate(Action action)
  775. {
  776. if (action == null) return 0;
  777. var stopwatch = new Stopwatch();
  778. stopwatch.Start();
  779. action.Invoke();
  780. stopwatch.Stop();
  781. return stopwatch.ElapsedMilliseconds;
  782. }
  783. #endregion
  784. #region Console
  785. /// <summary>获取或设置控制台标题。</summary>
  786. public static string Title
  787. {
  788. get { try { return Console.Title; } catch { return null; } }
  789. set { try { Console.Title = value; } catch { } }
  790. }
  791. /// <summary>设置在控制台中按 CTRL + C 时的方法。</summary>
  792. public static void CtrlCancel(Func<bool> exit)
  793. {
  794. const string postfix = " - 按 CTRL + C 可安全退出";
  795. var title = Title ?? "";
  796. if (!title.EndsWith(postfix))
  797. {
  798. title = title + postfix;
  799. Title = title;
  800. }
  801. if (exit == null) return;
  802. try { Console.CancelKeyPress += (s, e) => e.Cancel = !exit(); } catch { }
  803. }
  804. /// <summary>调用所有公共类,创建构造函数。</summary>
  805. /// <param name="assembly">要搜索类的程序集,指定为 NULL 时将获取当前程序集。</param>
  806. /// <param name="catchException">
  807. /// <para>指定为 TRUE 时将使用 TRY 语句捕获异常;</para>
  808. /// <para>指定为 FLASE 时发生异常将可能中断执行,可用于调试。</para></param>
  809. public static void InvokePublicClass(Assembly assembly = null, bool catchException = false)
  810. {
  811. const string Title = "Invoing Public Class";
  812. RuntimeUtility.Title = Title;
  813. var before = DateTime.Now;
  814. Logger.Internals.Info(typeof(RuntimeUtility), "Started Invoke.");
  815. var types = GetTypes(assembly ?? Assembly.GetCallingAssembly());
  816. foreach (var type in types)
  817. {
  818. if (!type.IsClass) continue;
  819. if (!type.IsPublic) continue;
  820. if (!CanNew(type)) continue;
  821. Logger.Internals.Info(typeof(RuntimeUtility), "Invoke " + type.FullName);
  822. RuntimeUtility.Title = type.FullName;
  823. try
  824. {
  825. Activator.CreateInstance(type);
  826. }
  827. catch (Exception ex)
  828. {
  829. var ex2 = ex.InnerException ?? ex;
  830. Logger.Internals.Exception(typeof(RuntimeUtility), ex2);
  831. if (!catchException) throw ex2;
  832. }
  833. }
  834. RuntimeUtility.Title = Title;
  835. var after = DateTime.Now;
  836. var span = after - before;
  837. var milli = Convert.ToInt64(span.TotalMilliseconds);
  838. var duration = $"{milli / 1000D} 秒";
  839. var result = "Finished Invoke.\n\n";
  840. result += $" Duration: {duration}\n";
  841. result += $" Started: {before.Lucid()}\n";
  842. result += $" Ended: {after.Lucid()}\n";
  843. Logger.Internals.Info(typeof(RuntimeUtility), result);
  844. }
  845. #endregion
  846. #region System
  847. /// <summary>结束当前进程。</summary>
  848. public static void Exit() => Process.GetCurrentProcess().Kill();
  849. /// <summary>当前操作系统是 Windows。</summary>
  850. public static bool IsWindows
  851. {
  852. #if NETFRAMEWORK
  853. get => Environment.OSVersion.Platform == PlatformID.Win32NT;
  854. #else
  855. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
  856. #endif
  857. }
  858. /// <summary>当前操作系统是 OS X 或 macOS。</summary>
  859. public static bool IsOSX
  860. {
  861. #if NETFRAMEWORK
  862. get => Environment.OSVersion.Platform == PlatformID.MacOSX;
  863. #else
  864. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX);
  865. #endif
  866. }
  867. /// <summary>当前操作系统是 Linux。</summary>
  868. public static bool IsLinux
  869. {
  870. #if NETFRAMEWORK
  871. get => Environment.OSVersion.Platform == PlatformID.Unix;
  872. #else
  873. get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux);
  874. #endif
  875. }
  876. #endregion
  877. #region Exception
  878. /// <summary>读取调用堆栈。</summary>
  879. public static string[] StackTrace()
  880. {
  881. var trace = new StackTrace(true);
  882. var frames = trace.GetFrames();
  883. var ab = new ArrayBuilder<string>();
  884. foreach (var frame in frames)
  885. {
  886. // 滤除当前方法。
  887. var method = frame.GetMethod();
  888. if (method == null) continue;
  889. var type = method.DeclaringType;
  890. if (type == null) continue;
  891. var value = $"{method.DeclaringType.FullName}.{method.Name}";
  892. ab.Add(value);
  893. }
  894. return ab.Export();
  895. }
  896. internal static string Message(Exception ex)
  897. {
  898. if (ex == null) return null;
  899. try
  900. {
  901. var message = ex.Message;
  902. if (!string.IsNullOrEmpty(message)) return message;
  903. var typeName = ex.GetType().FullName;
  904. message = $"异常 <{typeName}> 包含空消息。";
  905. return message;
  906. }
  907. catch
  908. {
  909. var typeName = ex.GetType().FullName;
  910. return $"获取 <{typeName}> 的消息时再次发生了异常。";
  911. }
  912. }
  913. #endregion
  914. }
  915. }