using Apewer.Internals; using Apewer.Models; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using System.Collections; using System.Text; namespace Apewer { /// 运行时实用工具。 public static class RuntimeUtility { /// 使用默认比较器判断相等。 public static bool Equals(T a, T b) => EqualityComparer.Default.Equals(a, b); #region 反射操作 /// 从外部加载对象。 public static object CreateObject(string path, string type, bool ignoreCase) { try { var a = Assembly.LoadFrom(path); var t = a.GetType(type, false, ignoreCase); if (t != null) { var result = Activator.CreateInstance(t); return result; } } catch { } return null; } /// 对每个属性执行动作。 public static void ForEachProperties(object instance, Action action, bool withNonPublic = true, bool withStatic = false) { if (instance == null || action == null) return; var type = instance.GetType(); if (type == null) return; var properties = new List(); properties.AddRange(type.GetProperties()); if (withNonPublic) properties.AddRange(type.GetProperties(BindingFlags.NonPublic)); foreach (var info in properties) { var arg = new Property() { Instance = instance, Type = type, Information = info, Getter = info.GetGetMethod(), Setter = info.GetSetMethod() }; if (arg.IsStatic && !withStatic) continue; action.Invoke(arg); } } #endregion #region Type /// 判断指定类型可序列化。 public static bool CanSerialize(Type type, bool inherit = false) { if (type == null) return false; var nsas = type.GetCustomAttributes(typeof(NonSerializedAttribute), inherit); if (nsas != null && nsas.Length > 0) return false; var sas = type.GetCustomAttributes(typeof(SerializableAttribute), inherit); if (sas != null && sas.Length > 0) return true; var tas = type.GetCustomAttributes(typeof(Source.TableAttribute), inherit); if (tas != null && tas.Length > 0) return true; return false; } /// 获取类型的完整名称。 public static string FullName(Type type) { if (type == null) return null; var sb = new StringBuilder(); var ns = type.Namespace; if (!string.IsNullOrEmpty(ns)) { sb.Append(ns); sb.Append("."); } var name = type.Name; var g = name.IndexOf('`'); if (g > -1) name = name.Substring(0, g); sb.Append(name); var gts = type.GetGenericArguments(); if (gts != null && gts.Length > 0) { var ts = new List(gts.Length); foreach (var gt in gts) ts.Add(FullName(gt)); sb.Append("<"); sb.Append(string.Join(",", ts.ToArray())); sb.Append(">"); } return sb.ToString(); } /// 检查类型。 public static bool TypeEquals(object instance, Type type) { if (instance == null) return type == null ? true : false; if (instance is PropertyInfo) { return ((PropertyInfo)instance).PropertyType.Equals(type); } if (instance is MethodInfo) { return ((MethodInfo)instance).ReturnType.Equals(type); } return instance.GetType().Equals(type); } /// 检查类型。 public static bool TypeEquals(object instance) => TypeEquals(instance, typeof(T)); /// 获取指定的首个特性,特性不存在时返回 Null 值。 public static T GetAttribute(object target) where T : Attribute { if (target == null) return null; try { return GetAttribute(target.GetType()); } catch { return null; } } /// 获取指定的首个特性,特性不存在时返回 Null 值。 public static T GetAttribute(Type target, bool inherit = false) where T : Attribute { if (target == null) return null; try { var type = target; var attributes = type.GetCustomAttributes(typeof(T), inherit); if (attributes.LongLength > 0L) { var attribute = attributes[0] as T; return attribute; } } catch { } return null; } /// 获取指定的首个特性,特性不存在时返回 Null 值。 public static T GetAttribute(PropertyInfo property, bool inherit = false) where T : Attribute { if (property == null) return null; try { var type = property; var attributes = type.GetCustomAttributes(typeof(T), inherit); if (attributes.LongLength > 0L) { var attribute = attributes[0] as T; return attribute; } } catch { } return null; } /// 获取指定的首个特性,特性不存在时返回 Null 值。 public static T GetAttribute(MethodInfo methods, bool inherit = false) where T : Attribute { if (methods == null) return null; try { var type = methods; var attributes = type.GetCustomAttributes(typeof(T), inherit); if (attributes.LongLength > 0L) { var attribute = attributes[0] as T; return attribute; } } catch { } return null; } /// 获取一个值,指示该属性是否 static。 public static bool IsStatic(PropertyInfo property, bool withNonPublic = false) { if (property == null) return false; var getter = property.GetGetMethod(); if (getter != null) return getter.IsStatic; if (withNonPublic) { getter = property.GetGetMethod(true); if (getter != null) return getter.IsStatic; } var setter = property.GetSetMethod(); if (setter != null) return setter.IsStatic; if (withNonPublic) { setter = property.GetSetMethod(true); if (setter != null) return setter.IsStatic; } return false; } /// 调用方法。 /// /// /// /// /// /// /// public static object Invoke(this MethodInfo method, object instance, params object[] parameters) { if (instance == null || method == null) return null; var pis = method.GetParameters(); if (pis == null || pis.Length < 1) return method.Invoke(instance, null); if (parameters == null) return method.Invoke(instance, null); return method.Invoke(instance, parameters); } /// 调用泛型对象的 ToString() 方法。 public static string ToString(T target) { var type = typeof(T); var methods = type.GetMethods(); foreach (var method in methods) { if (method.Name != "ToString") continue; if (method.GetParameters().LongLength > 0L) continue; var result = (string)method.Invoke(target, null); return result; } return null; } /// 获取属性值。 /// /// /// /// /// /// /// public static T InvokeGet(object instance, PropertyInfo property) { if (instance == null || property == null || !property.CanRead) return default; #if NET20 || NET40 || NET461 var getter = property.GetGetMethod(); if (getter != null) { try { var value = getter.Invoke(instance, null); if (value != null) { return (T)value; } } catch { } } return default; #else var value = property.GetValue(instance); try { return (T)value; } catch { return default; } #endif } /// 设置属性值。 /// /// /// /// /// /// /// public static void InvokeSet(object instance, PropertyInfo property, T value) { if (instance == null || property == null || !property.CanWrite) return; #if NET20 || NET40 var setter = property.GetSetMethod(); if (setter != null) { try { setter.Invoke(instance, new object[] { value }); } catch { } } #else property.SetValue(instance, value); #endif } /// 指示方法是否存在于指定类型中。 public static bool ExistIn(MethodInfo method, Type type) { if (method == null) return false; if (type == null) return false; return type.Equals(method.DeclaringType.Equals(type)); } /// 指示方法是否存在于指定类型中。 public static bool ExistIn(MethodInfo method) { if (method == null) return false; var type = typeof(T); return type.Equals(method.DeclaringType.Equals(type)); } /// 判断指定类型具有特性。 private static bool Contains(object[] attributes) where T : Attribute { if (attributes == null) return false; if (attributes.Length < 1) return false; var type = typeof(T); foreach (var attribute in attributes) { if (type.Equals(attribute.GetType())) return true; } return false; } /// 判断指定类型具有特性。 public static bool Contains(ICustomAttributeProvider model, bool inherit = false) where T : Attribute { if (model == null) return false; var attributes = model.GetCustomAttributes(inherit); return Contains(attributes); } /// 判断基类。 public static bool IsInherits(Type child, Type @base) { // 检查参数。 if (child == null || @base == null) return false; if (child == @base) return false; // 检查 interface 类型。 if (@base.IsInterface) return @base.IsAssignableFrom(child); // 忽略 System.Object。 var quantum = typeof(object); if (@base.Equals(quantum)) return true; if (child.Equals(quantum)) return false; // 循环判断基类。 var current = child; while (true) { var parent = current.BaseType; if (parent == null) return false; if (parent.Equals(@base)) return true; if (parent.Equals(quantum)) break; current = parent; } return false; } /// public static Type[] GetTypes(Assembly assembly, bool onlyExported = false) { if (assembly == null) return null; try { return onlyExported ? assembly.GetExportedTypes() : assembly.GetTypes(); } catch { } return new Type[0]; } /// 能从外部创建对象实例。 public static bool CanNew() => CanNew(typeof(T)); /// 能从外部创建对象实例。 public static bool CanNew(Type type) { if (type == null) return false; if (!type.IsClass && !type.IsValueType) return false; if (type.IsAbstract) return false; var constructors = type.GetConstructors(); foreach (var i in constructors) { if (i.IsPublic) { var parameters = i.GetParameters(); if (parameters.Length < 1) { return true; } } } return false; } /// 获取指定类型的默认值。 public static object Default(Type type) { if (type == null || !type.IsValueType) return null; return Activator.CreateInstance(type); } /// 判断指定对象是否为默认值。 public static bool IsDefault(object value) { if (value.IsNull()) return true; var type = value.GetType(); if (type.IsValueType) return value.Equals(Activator.CreateInstance(type)); return false; } /// 在程序集中枚举派生类型,可自定义检查器。 public static Type[] DerivedTypes(Type baseType, Assembly assembly, Func checker) { if (baseType == null) return new Type[0]; if (assembly == null) return new Type[0]; var types = GetTypes(assembly); var list = new List(types.Length); foreach (var type in types) { if (!IsInherits(type, baseType)) continue; if (checker != null && !checker(type)) continue; list.Add(type); } return list.ToArray(); } /// 是匿名类型。 /// public static bool IsAnonymousType(Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); // 类型是由编译器生成。 if (!Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)) return false; // 是泛型。 if (!type.IsGenericType) return false; // 名称。 if (!type.Name.StartsWith("<>") || !type.Name.Contains("AnonymousType")) return false; // 私有。 if (type.IsPublic) return false; return true; } /// 获取数组元素的类型。 /// 参数必须是正确的数组类型。 /// /// public static Type GetTypeOfArrayItem(Type arrayType) { if (arrayType == null) throw new ArgumentNullException(nameof(arrayType)); if (!arrayType.BaseType.Equals(typeof(Array))) throw new ArgumentException($"参数 {arrayType} 不是有效的数组类型。"); var methods = arrayType.GetMethods(); foreach (var method in methods) { if (method.Name.ToLower() != "set") continue; var parameters = method.GetParameters(); if (parameters.Length != 2) continue; var length = parameters[0].ParameterType; if (!length.Equals(typeof(int))) continue; var item = parameters[1].ParameterType; return item; } throw new ArgumentException($"参数 {arrayType} 不是有效的数组类型。"); } /// 是 Nullable<T> 类型。 public static bool IsNullableType(this Type type) { if (type.IsGenericType && !type.IsGenericTypeDefinition) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if ((object)genericTypeDefinition == typeof(Nullable<>)) { return true; } } return false; } /// 是 Nullable<T> 类型。 public static bool IsNullableType(this Type type, out Type genericType) { if (type.IsGenericType && !type.IsGenericTypeDefinition) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if ((object)genericTypeDefinition == typeof(Nullable<>)) { genericType = type.GetGenericArguments()[0]; return true; } } genericType = null; return false; } /// 获取 Nullable<T> 实例的值。 public static object GetNullableValue(object nullable) { var type = typeof(Nullable<>); var property = type.GetProperty("Value"); var getter = property.GetGetMethod(); var value = getter.Invoke(nullable, null); return value; } #endregion #region Collect & Dispose /// 控制系统垃圾回收器(一种自动回收未使用内存的服务)。强制对所有代进行即时垃圾回收。 public static void Collect() => GC.Collect(); /// 执行与释放或重置非托管资源关联的应用程序定义的任务。 /// 可能出现的错误信息。 public static void Dispose(object instance, bool flush = false) { if (instance == null) return; var stream = instance as Stream; if (stream != null) { if (flush) { try { stream.Flush(); } catch { } } try { stream.Close(); } catch { } } var disposable = instance as IDisposable; if (disposable != null) { try { disposable.Dispose(); } catch { } } } /// 执行与释放或重置非托管资源关联的应用程序定义的任务。 /// 可能出现的错误信息。 public static void Dispose(IEnumerable objects, bool flush = false) { if (objects != null) { foreach (var i in objects) Dispose(i, flush); } } #endregion #region Thread /// 停止线程。 public static void Abort(Thread thread) { if (thread == null) return; try { if (thread.IsAlive) thread.Abort(); } catch { } } /// 阻塞当前线程,时长以毫秒为单位。 public static void Sleep(int milliseconds) { if (milliseconds > 0) Thread.Sleep(milliseconds); } private static void Invoke(Action action, bool @try = false) { if (action == null) return; if (@try) { try { action.Invoke(); } catch { } } else { action.Invoke(); } } /// 在后台线程中执行,指定 Try 将忽略 Action 抛出的异常。 /// 要执行的 Action。 /// 忽略 Action 抛出的异常。 /// 对返回的 Thread 调用 Abort 可结束线程的执行。 [MethodImpl(MethodImplOptions.NoInlining)] public static Thread InBackground(Action action, bool @try = false) { if (action == null) return null; var thread = new Thread(delegate (object v) { Invoke(() => ((Action)v)(), @try); }); thread.IsBackground = true; thread.Start(action); return thread; } /// 启动线程,在新线程中执行。 /// 要执行的 Action。 /// 设置线程为后台线程。 /// 忽略 Action 抛出的异常。 /// 对返回的 Thread 调用 Abort 可结束线程的执行。 public static Thread StartThread(Action action, bool background = false, bool @try = false) { if (action == null) return null; var thread = new Thread(new ThreadStart(() => Invoke(action, @try))); thread.IsBackground = background; thread.Start(); return thread; } /// 经过指定时间(以毫秒为单位)后,在新线程(后台)中执行。 /// 要执行的 Action。 /// 调用 Action 之前延迟的时间量(以毫秒为单位)。 /// 忽略 Action 抛出的异常。 /// 对返回的 Timer 调用 Dispose 可终止计时器,阻止调用。 public static Timer Timeout(Action action, int delay, bool @try = false) { if (action == null) return null; return new Timer((x) => Invoke((Action)x, @try), action, delay > 0 ? delay : 0, -1); } /// 尝试在主线程调用。 /// /// public static void OnMainThread(Action action) { if (action == null) throw new ArgumentNullException(nameof(action)); var context = SynchronizationContext.Current; if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。"); context.Send(state => { action.Invoke(); }, null); } /// 尝试在主线程调用。 /// /// public static TResult OnMainThread(Func func) { if (func == null) throw new ArgumentNullException(nameof(func)); var context = SynchronizationContext.Current; if (context == null) throw new InvalidOperationException("未获取到当前线程的同步上下文。"); var result = default(TResult); context.Send(state => result = func.Invoke(), null); return result; } #endregion #region Assembly /// 列出当前域中的程序集。 public static Assembly[] ListLoadedAssemblies() { return AppDomain.CurrentDomain.GetAssemblies(); } /// 从指定的程序集加载资源。 /// 资源的名称。 /// 程序集,为 NULL 值时指向 CallingAssembly。 /// 该资源的流,发生错误时返回 NULL 值。 /// 此方法不引发异常。 public static Stream OpenResource(string name, Assembly assembly = null) { var stream = null as Stream; try { var asm = assembly ?? Assembly.GetCallingAssembly(); stream = asm.GetManifestResourceStream(name); } catch { } return null; } /// 从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。 /// 资源的名称。 /// 程序集,为 NULL 值时指向 CallingAssembly。 /// 该资源的流,发生错误时返回 NULL 值。 /// 此方法不引发异常。 public static MemoryStream GetResource(string name, Assembly assembly = null) { var res = OpenResource(name, assembly); if (res == null) return null; var memory = new MemoryStream(); BytesUtility.Read(res, memory); res.Dispose(); return memory; } #if NETFRAMEWORK /// 将代码生成为程序集。 public static Assembly Compile(string code, bool executable = false, bool inMemory = true) { using (var cdp = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("C#")) { var cp = new System.CodeDom.Compiler.CompilerParameters(); cp.ReferencedAssemblies.Add(typeof(void).Assembly.Location); cp.GenerateExecutable = false; cp.GenerateInMemory = true; cp.TempFiles = new System.CodeDom.Compiler.TempFileCollection(System.IO.Path.GetTempPath()); var cr = cdp.CompileAssemblyFromSource(cp, code); if (cr.Errors.Count > 0) throw new Exception(cr.Errors[0].ErrorText); var assembly = cr.CompiledAssembly; return assembly; } } #endif #endregion #region Application private static Class _AppPath = null; private static Class _DataPath = null; private static Class _InIIS = null; /// 当前应用程序由 IIS 托管。 private static bool InIIS() { if (_InIIS != null) return _InIIS.Value; var dll = Path.GetFileName(Assembly.GetExecutingAssembly().Location); var path1 = StorageUtility.CombinePath(ApplicationPath, dll); if (!File.Exists(path1)) { var path2 = StorageUtility.CombinePath(ApplicationPath, "bin", dll); if (File.Exists(path2)) { _InIIS = new Class(true); return true; } } _InIIS = new Class(false); return false; } /// 获取当前应用程序所在目录的路径。 /// /// 程序示例: D:\App /// 网站示例: D:\Website /// public static string ApplicationPath { get { var temp = _AppPath; if (!temp) { // AppDomain.CurrentDomain.BaseDirectory // AppDomain.CurrentDomain.SetupInformation.ApplicationBase // return AppDomain.CurrentDomain.BaseDirectory; #if NETSTD var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); #else var path = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; #endif temp = new Class(path); _AppPath = temp; } return temp.Value; } } /// 获取数据目录的路径。 public static string DataPath { get { var temp = _DataPath; if (!temp) { var app = ApplicationPath; // 网站使用 App_Data 目录。 var appData = Path.Combine(app, "app_data"); if (Directory.Exists(appData)) { temp = new Class(appData); } else if (File.Exists(Path.Combine(app, "web.config"))) { StorageUtility.AssureDirectory(appData); temp = new Class(appData); } else { // 获取并创建 Data 目录。 var data = Path.Combine(app, "data"); if (StorageUtility.AssureDirectory(data)) temp = new Class(data); else temp = new Class(app); } _DataPath = temp; } return temp.Value; } } /// 获取可执行文件的路径。 /// /// 调用: System.Windows.Forms.Application.ExecutablePath /// 示例: c:\windows\system32\inetsrv\w3wp.exe /// public static string ExecutablePath { get { var entry = Assembly.GetEntryAssembly(); if (entry == null) return null; var escapedCodeBase = entry.EscapedCodeBase; var uri = new Uri(escapedCodeBase); if (uri.Scheme == "file") return uri.LocalPath + uri.Fragment; return uri.ToString(); } } /// /// System.AppDomain.CurrentDomain.BaseDirectory /// D:\Website\ /// private static string CurrentDomainPath { get { return AppDomain.CurrentDomain.BaseDirectory; } } /// /// System.IO.Directory.GetCurrentDirectory() /// c:\windows\system32\inetsrv /// private static string CurrentDirectory { get { return Directory.GetCurrentDirectory(); } // System.Environment.CurrentDirectory } /// /// System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName /// c:\windows\system32\inetsrv\w3wp.exe /// private static string ProcessMainModule { get { return Process.GetCurrentProcess().MainModule.FileName; } } #endregion #region Evaluate /// 评估 Action 的执行时间,单位为毫秒。 public static long Evaluate(Action action) { if (action == null) return 0; var stopwatch = new Stopwatch(); stopwatch.Start(); action.Invoke(); stopwatch.Stop(); return stopwatch.ElapsedMilliseconds; } #endregion #region Console /// 获取或设置控制台标题。 public static string Title { get { try { return Console.Title; } catch { return null; } } set { try { Console.Title = value; } catch { } } } /// 设置在控制台中按 CTRL + C 时的方法。 public static void CtrlCancel(Func exit) { const string postfix = " - 按 CTRL + C 可安全退出"; var title = Title ?? ""; if (!title.EndsWith(postfix)) { title = title + postfix; Title = title; } if (exit == null) return; try { Console.CancelKeyPress += (s, e) => e.Cancel = !exit(); } catch { } } /// 调用所有公共类,创建构造函数。 /// 要搜索类的程序集,指定为 NULL 时将获取当前程序集。 /// /// 指定为 TRUE 时将使用 TRY 语句捕获异常; /// 指定为 FLASE 时发生异常将可能中断执行,可用于调试。 public static void InvokePublicClass(Assembly assembly = null, bool catchException = false) { const string Title = "Invoing Public Class"; RuntimeUtility.Title = Title; var before = DateTime.Now; Logger.Internals.Info(typeof(RuntimeUtility), "Started Invoke."); var types = GetTypes(assembly ?? Assembly.GetCallingAssembly()); foreach (var type in types) { if (!type.IsClass) continue; if (!type.IsPublic) continue; if (!CanNew(type)) continue; Logger.Internals.Info(typeof(RuntimeUtility), "Invoke " + type.FullName); RuntimeUtility.Title = type.FullName; try { Activator.CreateInstance(type); } catch (Exception ex) { var ex2 = ex.InnerException ?? ex; Logger.Internals.Exception(typeof(RuntimeUtility), ex2); if (!catchException) throw ex2; } } RuntimeUtility.Title = Title; var after = DateTime.Now; var span = after - before; var milli = Convert.ToInt64(span.TotalMilliseconds); var duration = $"{milli / 1000D} 秒"; var result = "Finished Invoke.\n\n"; result += $" Duration: {duration}\n"; result += $" Started: {before.Lucid()}\n"; result += $" Ended: {after.Lucid()}\n"; Logger.Internals.Info(typeof(RuntimeUtility), result); } #endregion #region System /// 结束当前进程。 public static void Exit() => Process.GetCurrentProcess().Kill(); /// 当前操作系统是 Windows。 public static bool IsWindows { #if NETFRAMEWORK get => Environment.OSVersion.Platform == PlatformID.Win32NT; #else get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows); #endif } /// 当前操作系统是 OS X 或 macOS。 public static bool IsOSX { #if NETFRAMEWORK get => Environment.OSVersion.Platform == PlatformID.MacOSX; #else get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.OSX); #endif } /// 当前操作系统是 Linux。 public static bool IsLinux { #if NETFRAMEWORK get => Environment.OSVersion.Platform == PlatformID.Unix; #else get => System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Linux); #endif } #endregion #region Exception /// 读取调用堆栈。 public static string[] StackTrace() { var trace = new StackTrace(true); var frames = trace.GetFrames(); var ab = new ArrayBuilder(); foreach (var frame in frames) { // 滤除当前方法。 var method = frame.GetMethod(); if (method == null) continue; var type = method.DeclaringType; if (type == null) continue; var value = $"{method.DeclaringType.FullName}.{method.Name}"; ab.Add(value); } return ab.Export(); } internal static string Message(Exception ex) { if (ex == null) return null; try { var message = ex.Message; if (!string.IsNullOrEmpty(message)) return message; var typeName = ex.GetType().FullName; message = $"异常 <{typeName}> 包含空消息。"; return message; } catch { var typeName = ex.GetType().FullName; return $"获取 <{typeName}> 的消息时再次发生了异常。"; } } #endregion } }