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
}
}