using NCC.Dependency; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace NCC.Extensions { /// /// 对象拓展类 /// [SuppressSniffer] public static class ObjectExtensions { /// /// 将 DateTimeOffset 转换成本地 DateTime /// /// /// public static DateTime ConvertToDateTime(this DateTimeOffset dateTime) { if (dateTime.Offset.Equals(TimeSpan.Zero)) return dateTime.UtcDateTime; if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime))) return dateTime.ToLocalTime().DateTime; else return dateTime.DateTime; } /// /// 将 DateTime 转换成 DateTimeOffset /// /// /// public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime) { return DateTime.SpecifyKind(dateTime, DateTimeKind.Local); } /// /// 判断是否是富基元类型 /// /// 类型 /// internal static bool IsRichPrimitive(this Type type) { // 处理元组类型 if (type.IsValueTuple()) return false; // 处理数组类型,基元数组类型也可以是基元类型 if (type.IsArray) return type.GetElementType().IsRichPrimitive(); // 基元类型或值类型或字符串类型 if (type.IsPrimitive || type.IsValueType || type == typeof(string)) return true; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) return type.GenericTypeArguments[0].IsRichPrimitive(); return false; } /// /// 合并两个字典 /// /// /// 字典 /// 新字典 /// internal static Dictionary AddOrUpdate(this Dictionary dic, Dictionary newDic) { foreach (var key in newDic.Keys) { if (dic.ContainsKey(key)) dic[key] = newDic[key]; else dic.Add(key, newDic[key]); } return dic; } /// /// 合并两个字典 /// /// /// 字典 /// 新字典 internal static void AddOrUpdate(this ConcurrentDictionary dic, Dictionary newDic) { foreach (var (key, value) in newDic) { dic.AddOrUpdate(key, value, (key, old) => value); } } /// /// 判断是否是元组类型 /// /// 类型 /// internal static bool IsValueTuple(this Type type) { return type.ToString().StartsWith(typeof(ValueTuple).FullName); } /// /// 判断方法是否是异步 /// /// 方法 /// internal static bool IsAsync(this MethodInfo method) { return method.GetCustomAttribute() != null || method.ReturnType.ToString().StartsWith(typeof(Task).FullName); } /// /// 判断类型是否实现某个泛型 /// /// 类型 /// 泛型类型 /// bool internal static bool HasImplementedRawGeneric(this Type type, Type generic) { // 检查接口类型 var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType); if (isTheRawGenericType) return true; // 检查类型 while (type != null && type != typeof(object)) { isTheRawGenericType = IsTheRawGenericType(type); if (isTheRawGenericType) return true; type = type.BaseType; } return false; // 判断逻辑 bool IsTheRawGenericType(Type type) => generic == (type.IsGenericType ? type.GetGenericTypeDefinition() : type); } /// /// 判断是否是匿名类型 /// /// 对象 /// internal static bool IsAnonymous(this object obj) { var type = obj.GetType(); return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) && type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) && type.Attributes.HasFlag(TypeAttributes.NotPublic); } /// /// 获取所有祖先类型 /// /// /// internal static IEnumerable GetAncestorTypes(this Type type) { var ancestorTypes = new List(); while (type != null && type != typeof(object)) { if (IsNoObjectBaseType(type)) { var baseType = type.BaseType; ancestorTypes.Add(baseType); type = baseType; } else break; } return ancestorTypes; static bool IsNoObjectBaseType(Type type) => type.BaseType != typeof(object); } /// /// 获取方法真实返回类型 /// /// /// internal static Type GetRealReturnType(this MethodInfo method) { // 判断是否是异步方法 var isAsyncMethod = method.IsAsync(); // 获取类型返回值并处理 Task 和 Task 类型返回值 var returnType = method.ReturnType; return isAsyncMethod ? (returnType.GenericTypeArguments.FirstOrDefault() ?? typeof(void)) : returnType; } /// /// 将一个对象转换为指定类型 /// /// /// /// internal static T ChangeType(this object obj) { return (T)ChangeType(obj, typeof(T)); } /// /// 将一个对象转换为指定类型 /// /// 待转换的对象 /// 目标类型 /// 转换后的对象 internal static object ChangeType(this object obj, Type type) { if (type == null) return obj; if (type == typeof(string)) return obj?.ToString(); if (type == typeof(Guid) && obj != null) return Guid.Parse(obj.ToString()); if (obj == null) return type.IsValueType ? Activator.CreateInstance(type) : null; var underlyingType = Nullable.GetUnderlyingType(type); if (type.IsAssignableFrom(obj.GetType())) return obj; else if ((underlyingType ?? type).IsEnum) { if (underlyingType != null && string.IsNullOrWhiteSpace(obj.ToString())) return null; else return Enum.Parse(underlyingType ?? type, obj.ToString()); } // 处理DateTime -> DateTimeOffset 类型 else if (obj.GetType().Equals(typeof(DateTime)) && (underlyingType ?? type).Equals(typeof(DateTimeOffset))) { return ((DateTime)obj).ConvertToDateTimeOffset(); } // 处理 DateTimeOffset -> DateTime 类型 else if (obj.GetType().Equals(typeof(DateTimeOffset)) && (underlyingType ?? type).Equals(typeof(DateTime))) { return ((DateTimeOffset)obj).ConvertToDateTime(); } else if (typeof(IConvertible).IsAssignableFrom(underlyingType ?? type)) { try { return Convert.ChangeType(obj, underlyingType ?? type, null); } catch { return underlyingType == null ? Activator.CreateInstance(type) : null; } } else { var converter = TypeDescriptor.GetConverter(type); if (converter.CanConvertFrom(obj.GetType())) return converter.ConvertFrom(obj); var constructor = type.GetConstructor(Type.EmptyTypes); if (constructor != null) { var o = constructor.Invoke(null); var propertys = type.GetProperties(); var oldType = obj.GetType(); foreach (var property in propertys) { var p = oldType.GetProperty(property.Name); if (property.CanWrite && p != null && p.CanRead) { property.SetValue(o, ChangeType(p.GetValue(obj, null), property.PropertyType), null); } } return o; } } return obj; } /// /// 查找方法指定特性,如果没找到则继续查找声明类 /// /// /// /// /// internal static TAttribute GetFoundAttribute(this MethodInfo method, bool inherit) where TAttribute : Attribute { // 获取方法所在类型 var declaringType = method.DeclaringType; var attributeType = typeof(TAttribute); // 判断方法是否定义指定特性,如果没有再查找声明类 var foundAttribute = method.IsDefined(attributeType, inherit) ? method.GetCustomAttribute(inherit) : ( declaringType.IsDefined(attributeType, inherit) ? declaringType.GetCustomAttribute(inherit) : default ); return foundAttribute; } /// /// 格式化字符串 /// /// /// /// internal static string Format(this string str, params object[] args) { return args == null || args.Length == 0 ? str : string.Format(str, args); } /// /// 切割骆驼命名式字符串 /// /// /// internal static string[] SplitCamelCase(this string str) { if (str == null) return Array.Empty(); if (string.IsNullOrWhiteSpace(str)) return new string[] { str }; if (str.Length == 1) return new string[] { str }; return Regex.Split(str, @"(?=\p{Lu}\p{Ll})|(?<=\p{Ll})(?=\p{Lu})") .Where(u => u.Length > 0) .ToArray(); } /// /// JsonElement 转 Object /// /// /// internal static object ToObject(this JsonElement jsonElement) { switch (jsonElement.ValueKind) { case JsonValueKind.String: return jsonElement.GetString(); case JsonValueKind.Undefined: case JsonValueKind.Null: return default; case JsonValueKind.Number: return jsonElement.GetDecimal(); case JsonValueKind.True: case JsonValueKind.False: return jsonElement.GetBoolean(); case JsonValueKind.Object: var enumerateObject = jsonElement.EnumerateObject(); var dic = new Dictionary(); foreach (var item in enumerateObject) { dic.Add(item.Name, item.Value.ToObject()); } return dic; case JsonValueKind.Array: var enumerateArray = jsonElement.EnumerateArray(); var list = new List(); foreach (var item in enumerateArray) { list.Add(item.ToObject()); } return list; default: return default; } } /// /// 清除字符串前后缀 /// /// 字符串 /// 0:前后缀,1:后缀,-1:前缀 /// 前后缀集合 /// internal static string ClearStringAffixes(this string str, int pos = 0, params string[] affixes) { // 空字符串直接返回 if (string.IsNullOrWhiteSpace(str)) return str; // 空前后缀集合直接返回 if (affixes == null || affixes.Length == 0) return str; var startCleared = false; var endCleared = false; string tempStr = null; foreach (var affix in affixes) { if (string.IsNullOrWhiteSpace(affix)) continue; if (pos != 1 && !startCleared && str.StartsWith(affix, StringComparison.OrdinalIgnoreCase)) { tempStr = str[affix.Length..]; startCleared = true; } if (pos != -1 && !endCleared && str.EndsWith(affix, StringComparison.OrdinalIgnoreCase)) { var _tempStr = !string.IsNullOrWhiteSpace(tempStr) ? tempStr : str; tempStr = _tempStr.Substring(0, _tempStr.Length - affix.Length); endCleared = true; } if (startCleared && endCleared) break; } return !string.IsNullOrWhiteSpace(tempStr) ? tempStr : str; } } }