This commit is contained in:
owenchen committed 2026-05-12 10:09:31 +08:00
1 parent 31fbe199c1
commit 1c0c83af5f
469 files changed
+62544 -5

No files matched your search

@@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// <see cref="ClaimsIdentity"/>扩展操作类
/// </summary>
public static class ClaimsIdentityExtensions
{
/// <summary>
/// 获取指定类型的Claim值
/// </summary>
public static string GetClaimValueFirstOrDefault(this IIdentity identity, string type)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.FindFirst(type)?.Value;
}
/// <summary>
/// 获取指定类型的所有Claim值
/// </summary>
public static string[] GetClaimValues(this IIdentity identity, string type)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.Claims.Where(m => m.Type == type).Select(m => m.Value).ToArray();
}
/// <summary>
/// 获取用户ID
/// </summary>
public static T GetUserId<T>(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return default(T);
}
string value = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (value == null)
{
return default(T);
}
return value.CastTo<T>();
}
/// <summary>
/// 获取用户ID
/// </summary>
public static string GetUserId(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
/// <summary>
/// 获取用户名
/// </summary>
public static string GetUserName(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.FindFirst(ClaimTypes.Name)?.Value;
}
/// <summary>
/// 获取Email
/// </summary>
public static string GetEmail(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.FindFirst(ClaimTypes.Email)?.Value;
}
/// <summary>
/// 获取昵称
/// </summary>
public static string GetNickName(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return null;
}
return claimsIdentity.FindFirst(ClaimTypes.GivenName)?.Value;
}
/// <summary>
/// 移除指定类型的声明
/// </summary>
public static void RemoveClaim(this IIdentity identity, string claimType)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return;
}
Claim claim = claimsIdentity.FindFirst(claimType);
if (claim == null)
{
return;
}
claimsIdentity.RemoveClaim(claim);
}
/// <summary>
/// 获取所有角色
/// </summary>
public static string[] GetRoles(this IIdentity identity)
{
if (!(identity is ClaimsIdentity claimsIdentity))
{
return new string[0];
}
return claimsIdentity.FindAll(ClaimTypes.Role).SelectMany(m =>
{
string[] roles = m.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return roles;
}).ToArray();
}
}
}
@@ -0,0 +1,112 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// 集合类型字符串排序操作类
/// </summary>
/// <typeparam name="T">集合项类型</typeparam>
public static class CollectionPropertySorter<T>
{
// ReSharper disable StaticFieldInGenericType
private static readonly ConcurrentDictionary<string, LambdaExpression> Cache = new ConcurrentDictionary<string, LambdaExpression>();
/// <summary>
/// 按指定的属性名称对<see cref="IEnumerable{T}"/>序列进行排序
/// </summary>
/// <param name="source"><see cref="IEnumerable{T}"/>序列</param>
/// <param name="propertyName">属性名称</param>
/// <param name="sortDirection">排序方向</param>
public static IOrderedEnumerable<T> OrderBy(IEnumerable<T> source, string propertyName, ListSortDirection sortDirection)
{
propertyName.CheckNotNullOrEmpty("propertyName");
dynamic expression = GetKeySelector(propertyName);
dynamic keySelector = expression.Compile();
return sortDirection == ListSortDirection.Ascending
? Enumerable.OrderBy(source, keySelector)
: Enumerable.OrderByDescending(source, keySelector);
}
/// <summary>
/// 按指定的属性名称对<see cref="IOrderedEnumerable{T}"/>进行继续排序
/// </summary>
/// <param name="source"><see cref="IOrderedEnumerable{T}"/>序列</param>
/// <param name="propertyName">属性名称</param>
/// <param name="sortDirection">排序方向</param>
public static IOrderedEnumerable<T> ThenBy(IOrderedEnumerable<T> source, string propertyName, ListSortDirection sortDirection)
{
propertyName.CheckNotNullOrEmpty("propertyName");
dynamic expression = GetKeySelector(propertyName);
dynamic keySelector = expression.Compile();
return sortDirection == ListSortDirection.Ascending
? Enumerable.ThenBy(source, keySelector)
: Enumerable.ThenByDescending(source, keySelector);
}
/// <summary>
/// 按指定的属性名称对<see cref="IQueryable{T}"/>序列进行排序
/// </summary>
/// <param name="source">IQueryable{T}序列</param>
/// <param name="propertyName">属性名称</param>
/// <param name="sortDirection">排序方向</param>
/// <returns></returns>
public static IOrderedQueryable<T> OrderBy(IQueryable<T> source, string propertyName, ListSortDirection sortDirection)
{
propertyName.CheckNotNullOrEmpty("propertyName");
dynamic keySelector = GetKeySelector(propertyName);
return sortDirection == ListSortDirection.Ascending
? Queryable.OrderBy(source, keySelector)
: Queryable.OrderByDescending(source, keySelector);
}
/// <summary>
/// 按指定的属性名称对<see cref="IOrderedQueryable{T}"/>序列进行排序
/// </summary>
/// <param name="source">IOrderedQueryable{T}序列</param>
/// <param name="propertyName">属性名称</param>
/// <param name="sortDirection">排序方向</param>
/// <returns></returns>
public static IOrderedQueryable<T> ThenBy(IOrderedQueryable<T> source, string propertyName, ListSortDirection sortDirection)
{
propertyName.CheckNotNullOrEmpty("propertyName");
dynamic keySelector = GetKeySelector(propertyName);
return sortDirection == ListSortDirection.Ascending
? Queryable.ThenBy(source, keySelector)
: Queryable.ThenByDescending(source, keySelector);
}
private static LambdaExpression GetKeySelector(string keyName)
{
Type type = typeof(T);
string key = type.FullName + "." + keyName;
if (Cache.ContainsKey(key))
{
return Cache[key];
}
ParameterExpression param = Expression.Parameter(type);
string[] propertyNames = keyName.Split('.');
Expression propertyAccess = param;
foreach (string propertyName in propertyNames)
{
PropertyInfo property = type.GetProperty(propertyName);
if (property == null)
{
throw new Exception(string.Format("指定对象中不存在名称为“{0}”的属性。", propertyName));
}
type = property.PropertyType;
propertyAccess = Expression.MakeMemberAccess(propertyAccess, property);
}
LambdaExpression keySelector = Expression.Lambda(propertyAccess, param);
Cache[key] = keySelector;
return keySelector;
}
}
}
@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
using System;
using System.Collections.Concurrent;
using System.Reflection;
public static class CustomAttributeExtensions
{
/// <summary>
/// Cache Data
/// </summary>
private static readonly ConcurrentDictionary<string, object> Cache = new ConcurrentDictionary<string, object>();
/// <summary>
/// 获取CustomAttribute Value
/// </summary>
/// <typeparam name="TAttribute">Attribute的子类型</typeparam>
/// <typeparam name="TReturn">TReturn的子类型</typeparam>
/// <param name="sourceType">头部标有CustomAttribute类的类型</param>
/// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
/// <returns>返回Attribute的值,没有则返回null</returns>
public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction)
where TAttribute : Attribute
{
return _getAttributeValue(sourceType, attributeValueAction, null);
}
/// <summary>
/// 获取CustomAttribute Value
/// </summary>
/// <typeparam name="TAttribute">Attribute的子类型</typeparam>
/// <typeparam name="TReturn">TReturn的子类型</typeparam>
/// <param name="sourceType">头部标有CustomAttribute类的类型</param>
/// <param name="attributeValueAction">取Attribute具体哪个属性值的匿名函数</param>
/// <param name="propertyName">field name或property name</param>
/// <returns>返回Attribute的值,没有则返回null</returns>
public static TReturn GetCustomAttributeValue<TAttribute, TReturn>(this Type sourceType, Func<TAttribute, TReturn> attributeValueAction, string propertyName)
where TAttribute : Attribute
{
return _getAttributeValue(sourceType, attributeValueAction, propertyName);
}
#region private methods
private static TReturn _getAttributeValue<TAttribute, TReturn>(Type sourceType, Func<TAttribute, TReturn> attributeFunc, string propertyName)
where TAttribute : Attribute
{
var cacheKey = BuildKey<TAttribute>(sourceType, propertyName);
var value = Cache.GetOrAdd(cacheKey, k => GetValue(sourceType, attributeFunc, propertyName));
if (value is TReturn) return (TReturn)Cache[cacheKey];
return default(TReturn);
}
private static string BuildKey<TAttribute>(Type type, string propertyName) where TAttribute : Attribute
{
var attributeName = typeof(TAttribute).FullName;
if (string.IsNullOrEmpty(propertyName))
{
return type.FullName + "." + attributeName;
}
return type.FullName + "." + propertyName + "." + attributeName;
}
private static TReturn GetValue<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> attributeValueAction, string name)
where TAttribute : Attribute
{
TAttribute attribute = default(TAttribute);
if (string.IsNullOrEmpty(name))
{
attribute = type.GetCustomAttribute<TAttribute>(false);
}
else
{
var propertyInfo = type.GetProperty(name);
if (propertyInfo != null)
{
attribute = propertyInfo.GetCustomAttribute<TAttribute>(false);
}
else
{
var fieldInfo = type.GetField(name);
if (fieldInfo != null)
{
attribute = fieldInfo.GetCustomAttribute<TAttribute>(false);
}
else
{
var methodInfo = type.GetMethod(name);
if (methodInfo != null)
{
attribute = methodInfo.GetCustomAttribute<TAttribute>(false);
}
}
}
}
return attribute == null ? default(TReturn) : attributeValueAction(attribute);
}
#endregion
}
}
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// Enumerable集合扩展方法
/// </summary>
public static class EnumerableExtensions
{
/// <summary>
/// 打乱一个集合的项顺序
/// </summary>
public static IEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return source.OrderBy(m => Guid.NewGuid());
}
/// <summary>
/// 将集合展开并分别转换成字符串,再以指定的分隔符衔接,拼成一个字符串返回。默认分隔符为逗号
/// </summary>
/// <param name="collection"> 要处理的集合 </param>
/// <param name="separator"> 分隔符,默认为逗号 </param>
/// <returns> 拼接后的字符串 </returns>
public static string ExpandAndToString<T>(this IEnumerable<T> collection, string separator = ",")
{
return collection.ExpandAndToString(t => t?.ToString(), separator);
}
/// <summary>
/// 循环集合的每一项,调用委托生成字符串,返回合并后的字符串。默认分隔符为逗号
/// </summary>
/// <param name="collection">待处理的集合</param>
/// <param name="itemFormatFunc">单个集合项的转换委托</param>
/// <param name="separator">分隔符,默认为逗号</param>
/// <typeparam name="T">泛型类型</typeparam>
/// <returns></returns>
public static string ExpandAndToString<T>(this IEnumerable<T> collection, Func<T, string> itemFormatFunc, string separator = ",")
{
collection = collection as IList<T> ?? collection.ToList();
if (!collection.Any())
{
return string.Empty;
}
StringBuilder sb = new StringBuilder();
int i = 0;
int count = collection.Count();
foreach (T t in collection)
{
if (i == count - 1)
{
sb.Append(itemFormatFunc(t));
}
else
{
sb.Append(itemFormatFunc(t) + separator);
}
i++;
}
return sb.ToString();
}
/// <summary>
/// 集合是否为空
/// </summary>
/// <param name="collection"> 要处理的集合 </param>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <returns> 为空返回True,不为空返回False </returns>
public static bool IsEmpty<T>(this IEnumerable<T> collection)
{
collection = collection as IList<T> ?? collection.ToList();
return !collection.Any();
}
/// <summary>
/// 根据第三方条件是否为真来决定是否执行指定条件的查询
/// </summary>
/// <param name="source"> 要查询的源 </param>
/// <param name="predicate"> 查询条件 </param>
/// <param name="condition"> 第三方条件 </param>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <returns> 查询的结果 </returns>
public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool condition)
{
source = source as IList<T> ?? source.ToList();
return condition ? source.Where(predicate) : source;
}
/// <summary>
/// 将字符串集合按指定前缀排序
/// </summary>
public static IEnumerable<T> OrderByPrefixes<T>(this IEnumerable<T> source, Func<T, string> keySelector, params string[] prefixes)
{
List<T> all = source.OrderBy(keySelector).ToList();
List<T> result = new List<T>();
foreach (string prefix in prefixes)
{
List<T> tmpList = all.Where(m => keySelector(m).StartsWith(prefix)).OrderBy(keySelector).ToList();
all = all.Except(tmpList).ToList();
result.AddRange(tmpList);
}
result.AddRange(all);
return result;
}
/// <summary>
/// 根据指定条件返回集合中不重复的元素
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <typeparam name="TKey">动态筛选条件类型</typeparam>
/// <param name="source">要操作的源</param>
/// <param name="keySelector">重复数据筛选条件</param>
/// <returns>不重复元素的集合</returns>
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
source = source as IList<T> ?? source.ToList();
return source.GroupBy(keySelector).Select(group => group.First());
}
/// <summary>
/// 把<see cref="IEnumerable{T}"/>集合按指定字段与排序方式进行排序
/// </summary>
/// <typeparam name="T">集合项类型</typeparam>
/// <param name="source">要排序的数据集</param>
/// <param name="propertyName">排序属性名</param>
/// <param name="sortDirection">排序方向</param>
/// <returns>排序后的数据集</returns>
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source,
string propertyName,
ListSortDirection sortDirection = ListSortDirection.Ascending)
{
return CollectionPropertySorter<T>.OrderBy(source, propertyName, sortDirection);
}
/// <summary>
/// 把<see cref="IEnumerable{T}"/>集合按指定字段排序条件进行排序
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <param name="source">要排序的数据集</param>
/// <param name="sortCondition">列表字段排序条件</param>
/// <returns></returns>
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, SortCondition sortCondition)
{
return source.OrderBy(sortCondition.SortField, sortCondition.ListSortDirection);
}
/// <summary>
/// 把<see cref="IEnumerable{T}"/>集合按指定字段排序条件进行排序
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <param name="source">要排序的数据集</param>
/// <param name="sortCondition">列表字段排序条件</param>
/// <returns></returns>
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, SortCondition<T> sortCondition)
{
return source.OrderBy(sortCondition.SortField, sortCondition.ListSortDirection);
}
/// <summary>
/// 把<see cref="IOrderedQueryable{T}"/>集合继续按指定字段排序方式进行排序
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <param name="source">要排序的数据集</param>
/// <param name="propertyName">排序属性名</param>
/// <param name="sortDirection">排序方向</param>
/// <returns></returns>
public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source,
string propertyName,
ListSortDirection sortDirection = ListSortDirection.Ascending)
{
propertyName.CheckNotNullOrEmpty("propertyName");
return CollectionPropertySorter<T>.ThenBy(source, propertyName, sortDirection);
}
/// <summary>
/// 把<see cref="IOrderedEnumerable{T}"/>集合继续指定字段排序方式进行排序
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <param name="source">要排序的数据集</param>
/// <param name="sortCondition">列表字段排序条件</param>
/// <returns></returns>
public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, SortCondition sortCondition)
{
return source.ThenBy(sortCondition.SortField, sortCondition.ListSortDirection);
}
}
}
@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.StaticFiles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
public class FileExtension
{
public static FileExtensionContentTypeProvider GetFileExtensionContentTypeProvider()
{
var fileExtensionProvider = new FileExtensionContentTypeProvider();
fileExtensionProvider.Mappings[".iec"] = "application/octet-stream";
fileExtensionProvider.Mappings[".patch"] = "application/octet-stream";
fileExtensionProvider.Mappings[".apk"] = "application/vnd.android.package-archive";
fileExtensionProvider.Mappings[".pem"] = "application/x-x509-user-cert";
fileExtensionProvider.Mappings[".gzip"] = "application/x-gzip";
fileExtensionProvider.Mappings[".7zip"] = "application/zip";
fileExtensionProvider.Mappings[".jpg2"] = "image/jp2";
fileExtensionProvider.Mappings[".et"] = "application/kset";
fileExtensionProvider.Mappings[".dps"] = "application/ksdps";
fileExtensionProvider.Mappings[".cdr"] = "application/x-coreldraw";
fileExtensionProvider.Mappings[".shtml"] = "text/html";
fileExtensionProvider.Mappings[".php"] = "application/x-httpd-php";
fileExtensionProvider.Mappings[".php3"] = "application/x-httpd-php";
fileExtensionProvider.Mappings[".php4"] = "application/x-httpd-php";
fileExtensionProvider.Mappings[".phtml"] = "application/x-httpd-php";
fileExtensionProvider.Mappings[".pcd"] = "image/x-photo-cd";
fileExtensionProvider.Mappings[".bcmap"] = "application/octet-stream";
fileExtensionProvider.Mappings[".properties"] = "application/octet-stream";
fileExtensionProvider.Mappings[".m3u8"] = "application/x-mpegURL";
return fileExtensionProvider;
}
}
}
@@ -0,0 +1,315 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// 基类型<see cref="Object"/>扩展辅助操作类
/// </summary>
public static class ObjectExtensions
{
#region 公共方法
/// <summary>
/// 把对象类型转换为指定类型
/// </summary>
/// <param name="value"></param>
/// <param name="conversionType"></param>
/// <returns></returns>
public static object CastTo(this object value, Type conversionType)
{
if (value == null)
{
return null;
}
if (conversionType.IsNullableType())
{
conversionType = conversionType.GetUnNullableType();
}
if (conversionType.IsEnum)
{
return Enum.Parse(conversionType, value.ToString());
}
if (conversionType == typeof(Guid))
{
return Guid.Parse(value.ToString());
}
return Convert.ChangeType(value, conversionType);
}
/// <summary>
/// 把对象类型转化为指定类型
/// </summary>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <param name="value"> 要转化的源对象 </param>
/// <returns> 转化后的指定类型的对象,转化失败引发异常。 </returns>
public static T CastTo<T>(this object value)
{
if (value == null && default(T) == null)
{
return default(T);
}
if (value.GetType() == typeof(T))
{
return (T)value;
}
object result = CastTo(value, typeof(T));
return (T)result;
}
/// <summary>
/// 把对象类型转化为指定类型,转化失败时返回指定的默认值
/// </summary>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <param name="value"> 要转化的源对象 </param>
/// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
/// <returns> 转化后的指定类型对象,转化失败时返回指定的默认值 </returns>
public static T CastTo<T>(this object value, T defaultValue)
{
try
{
return CastTo<T>(value);
}
catch (Exception)
{
return defaultValue;
}
}
/// <summary>
/// 判断当前值是否介于指定范围内
/// </summary>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <param name="value"> 动态类型对象 </param>
/// <param name="start"> 范围起点 </param>
/// <param name="end"> 范围终点 </param>
/// <param name="leftEqual"> 是否可等于上限(默认等于) </param>
/// <param name="rightEqual"> 是否可等于下限(默认等于) </param>
/// <returns> 是否介于 </returns>
public static bool IsBetween<T>(this IComparable<T> value, T start, T end, bool leftEqual = true, bool rightEqual = true) where T : IComparable
{
bool flag = leftEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0;
return flag && (rightEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0);
}
/// <summary>
/// 判断当前值是否介于指定范围内
/// </summary>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <param name="value"> 动态类型对象 </param>
/// <param name="min">范围小值</param>
/// <param name="max">范围大值</param>
/// <param name="minEqual">是否可等于小值(默认等于)</param>
/// <param name="maxEqual">是否可等于大值(默认等于)</param>
public static bool IsInRange<T>(this IComparable<T> value, T min, T max, bool minEqual = true, bool maxEqual = true) where T : IComparable
{
bool flag = minEqual ? value.CompareTo(min) >= 0 : value.CompareTo(min) > 0;
return flag && (maxEqual ? value.CompareTo(max) <= 0 : value.CompareTo(max) < 0);
}
/// <summary>
/// 是否存在于
/// </summary>
public static bool IsIn<T>(this T value, params T[] source)
{
return source.Contains(value);
}
/// <summary>
/// 将对象[主要是匿名对象]转换为dynamic
/// </summary>
public static dynamic ToDynamic(this object value)
{
IDictionary<string, object> expando = new ExpandoObject();
Type type = value.GetType();
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(type);
foreach (PropertyDescriptor property in properties)
{
var val = property.GetValue(value);
if (property.PropertyType.FullName != null && property.PropertyType.FullName.StartsWith("<>f__AnonymousType"))
{
dynamic dval = val.ToDynamic();
expando.Add(property.Name, dval);
}
else
{
expando.Add(property.Name, val);
}
}
return (ExpandoObject)expando;
}
/// <summary>
/// 将 DateTimeOffset 转换成本地 DateTime
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 将 DateTimeOffset? 转换成本地 DateTime?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTime? ConvertToDateTime(this DateTimeOffset? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTime() : null;
}
/// <summary>
/// 将 DateTime 转换成 DateTimeOffset
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
{
return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
/// <summary>
/// 将 DateTime? 转换成 DateTimeOffset?
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static DateTimeOffset? ConvertToDateTimeOffset(this DateTime? dateTime)
{
return dateTime.HasValue ? dateTime.Value.ConvertToDateTimeOffset() : null;
}
/// <summary>
/// 将时间戳转换为 DateTime
/// </summary>
/// <param name="timestamp"></param>
/// <returns></returns>
internal static DateTime ConvertToDateTime(this long timestamp)
{
var timeStampDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var digitCount = (int)Math.Floor(Math.Log10(timestamp) + 1);
if (digitCount != 13 && digitCount != 10)
{
throw new ArgumentException("Data is not a valid timestamp format.");
}
return (digitCount == 13
? timeStampDateTime.AddMilliseconds(timestamp) // 13 位时间戳
: timeStampDateTime.AddSeconds(timestamp)).ToLocalTime(); // 10 位时间戳
}
/// <summary>
/// 将 IFormFile 转换成 byte[]
/// </summary>
/// <param name="formFile"></param>
/// <returns></returns>
//public static byte[] ToByteArray(this IFormFile formFile)
//{
// var fileLength = formFile.Length;
// using var stream = formFile.OpenReadStream();
// var bytes = new byte[fileLength];
// stream.Read(bytes, 0, (int)fileLength);
// return bytes;
//}
/// <summary>
/// 将流保存到本地磁盘
/// </summary>
/// <param name="stream"></param>
/// <param name="path"></param>
/// <returns></returns>
public static void CopyToSave(this Stream stream, string path)
{
// 空检查
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
using var fileStream = File.Create(path);
stream.CopyTo(fileStream);
}
/// <summary>
/// 将字节数组保存到本地磁盘
/// </summary>
/// <param name="bytes"></param>
/// <param name="path"></param>
/// <returns></returns>
public static void CopyToSave(this byte[] bytes, string path)
{
using var stream = new MemoryStream(bytes);
stream.CopyToSave(path);
}
/// <summary>
/// 将流保存到本地磁盘
/// </summary>
/// <param name="stream"></param>
/// <param name="path"></param>
/// <returns></returns>
public static async Task CopyToSaveAsync(this Stream stream, string path)
{
// 空检查
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path));
using var fileStream = File.Create(path);
await stream.CopyToAsync(fileStream);
}
/// <summary>
/// 将字节数组保存到本地磁盘
/// </summary>
/// <param name="bytes"></param>
/// <param name="path"></param>
/// <returns></returns>
public static async Task CopyToSaveAsync(this byte[] bytes, string path)
{
using var stream = new MemoryStream(bytes);
await stream.CopyToSaveAsync(path);
}
/// <summary>
/// 判断类型是否实现某个泛型
/// </summary>
/// <param name="type">类型</param>
/// <param name="generic">泛型类型</param>
/// <returns>bool</returns>
public 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);
}
#endregion
}
}
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// 用于参数检查的扩展方法
/// </summary>
public static class ParameterCheckExtensions
{
/// <summary>
/// 验证指定值的断言<paramref name="assertion"/>是否为真,如果不为真,抛出指定消息<paramref name="message"/>的指定类型<typeparamref name="TException"/>异常
/// </summary>
/// <typeparam name="TException">异常类型</typeparam>
/// <param name="assertion">要验证的断言。</param>
/// <param name="message">异常消息。</param>
private static void Require<TException>(bool assertion, string message) where TException : Exception
{
if (assertion)
{
return;
}
if (string.IsNullOrEmpty(message))
{
throw new ArgumentNullException("message");
}
TException exception = (TException)Activator.CreateInstance(typeof(TException), message);
throw exception;
}
/// <summary>
/// 验证指定值的断言表达式是否为真,不为值抛出<see cref="Exception"/>异常
/// </summary>
/// <param name="value"></param>
/// <param name="assertionFunc">要验证的断言表达式</param>
/// <param name="message">异常消息</param>
public static void Required<T>(this T value, Func<T, bool> assertionFunc, string message)
{
if (assertionFunc == null)
{
throw new ArgumentNullException("assertionFunc");
}
Require<Exception>(assertionFunc(value), message);
}
/// <summary>
/// 验证指定值的断言表达式是否为真,不为真抛出<typeparamref name="TException"/>异常
/// </summary>
/// <typeparam name="T">要判断的值的类型</typeparam>
/// <typeparam name="TException">抛出的异常类型</typeparam>
/// <param name="value">要判断的值</param>
/// <param name="assertionFunc">要验证的断言表达式</param>
/// <param name="message">异常消息</param>
public static void Required<T, TException>(this T value, Func<T, bool> assertionFunc, string message) where TException : Exception
{
if (assertionFunc == null)
{
throw new ArgumentNullException("assertionFunc");
}
Require<TException>(assertionFunc(value), message);
}
/// <summary>
/// 检查参数不能为空引用,否则抛出<see cref="ArgumentNullException"/>异常。
/// </summary>
/// <param name="value"></param>
/// <param name="paramName">参数名称</param>
/// <exception cref="ArgumentNullException"></exception>
public static void CheckNotNull<T>(this T value, string paramName) where T : class
{
Require<ArgumentNullException>(value != null, string.Format("参数“{0}”不能为空引用。", paramName));
}
/// <summary>
/// 检查字符串不能为空引用或空字符串,否则抛出<see cref="ArgumentNullException"/>异常或<see cref="ArgumentException"/>异常。
/// </summary>
/// <param name="value"></param>
/// <param name="paramName">参数名称。</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public static void CheckNotNullOrEmpty(this string value, string paramName)
{
value.CheckNotNull(paramName);
Require<ArgumentException>(value.Length > 0, string.Format("参数“{0}”不能为空引用或空字符串。", paramName));
}
/// <summary>
/// 检查Guid值不能为Guid.Empty,否则抛出<see cref="ArgumentException"/>异常。
/// </summary>
/// <param name="value"></param>
/// <param name="paramName">参数名称。</param>
/// <exception cref="ArgumentException"></exception>
public static void CheckNotEmpty(this Guid value, string paramName)
{
Require<ArgumentException>(value != Guid.Empty, string.Format("参数“{0}”的值不能为Guid.Empty", paramName));
}
/// <summary>
/// 检查集合不能为空引用或空集合,否则抛出<see cref="ArgumentNullException"/>异常或<see cref="ArgumentException"/>异常。
/// </summary>
/// <typeparam name="T">集合项的类型。</typeparam>
/// <param name="collection"></param>
/// <param name="paramName">参数名称。</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public static void CheckNotNullOrEmpty<T>(this IEnumerable<T> collection, string paramName)
{
collection.CheckNotNull(paramName);
Require<ArgumentException>(collection.Any(), string.Format("参数“{0}”不能为空引用或空集合。", paramName));
}
/// <summary>
/// 检查参数必须小于[或可等于,参数canEqual]指定值,否则抛出<see cref="ArgumentOutOfRangeException"/>异常。
/// </summary>
/// <typeparam name="T">参数类型。</typeparam>
/// <param name="value"></param>
/// <param name="paramName">参数名称。</param>
/// <param name="target">要比较的值。</param>
/// <param name="canEqual">是否可等于。</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void CheckLessThan<T>(this T value, string paramName, T target, bool canEqual = false) where T : IComparable<T>
{
bool flag = canEqual ? value.CompareTo(target) <= 0 : value.CompareTo(target) < 0;
string format = canEqual ? "参数“{0}”的值必须小于或等于“{1}”。" : "参数“{0}”的值必须小于“{1}”。";
Require<ArgumentOutOfRangeException>(flag, string.Format(format, paramName, target));
}
/// <summary>
/// 检查参数必须大于[或可等于,参数canEqual]指定值,否则抛出<see cref="ArgumentOutOfRangeException"/>异常。
/// </summary>
/// <typeparam name="T">参数类型。</typeparam>
/// <param name="value"></param>
/// <param name="paramName">参数名称。</param>
/// <param name="target">要比较的值。</param>
/// <param name="canEqual">是否可等于。</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void CheckGreaterThan<T>(this T value, string paramName, T target, bool canEqual = false) where T : IComparable<T>
{
bool flag = canEqual ? value.CompareTo(target) >= 0 : value.CompareTo(target) > 0;
string format = canEqual ? "参数“{0}”的值必须大于或等于“{1}”。" : "参数“{0}”的值必须大于“{1}”。";
Require<ArgumentOutOfRangeException>(flag, string.Format(format, paramName, target));
}
/// <summary>
/// 检查参数必须在指定范围之间,否则抛出<see cref="ArgumentOutOfRangeException"/>异常。
/// </summary>
/// <typeparam name="T">参数类型。</typeparam>
/// <param name="value"></param>
/// <param name="paramName">参数名称。</param>
/// <param name="start">比较范围的起始值。</param>
/// <param name="end">比较范围的结束值。</param>
/// <param name="startEqual">是否可等于起始值</param>
/// <param name="endEqual">是否可等于结束值</param>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static void CheckBetween<T>(this T value, string paramName, T start, T end, bool startEqual = false, bool endEqual = false)
where T : IComparable<T>
{
bool flag = startEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0;
string message = startEqual
? string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间。", paramName, start, end)
: string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。", paramName, start, end, start);
Require<ArgumentOutOfRangeException>(flag, message);
flag = endEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0;
message = endEqual
? string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间。", paramName, start, end)
: string.Format("参数“{0}”的值必须在“{1}”与“{2}”之间,且不能等于“{3}”。", paramName, start, end, end);
Require<ArgumentOutOfRangeException>(flag, message);
}
/// <summary>
/// 检查指定路径的文件夹必须存在,否则抛出<see cref="DirectoryNotFoundException"/>异常。
/// </summary>
/// <param name="directory"></param>
/// <param name="paramName">参数名称。</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="DirectoryNotFoundException"></exception>
public static void CheckDirectoryExists(this string directory, string paramName = null)
{
CheckNotNull(directory, paramName);
Require<DirectoryNotFoundException>(Directory.Exists(directory), string.Format("指定的目录路径“{0}”不存在。", directory));
}
/// <summary>
/// 检查指定路径的文件必须存在,否则抛出<see cref="FileNotFoundException"/>异常。
/// </summary>
/// <param name="filename"></param>
/// <param name="paramName">参数名称。</param>
/// <exception cref="ArgumentNullException">当文件路径为null时</exception>
/// <exception cref="FileNotFoundException">当文件路径不存在时</exception>
public static void CheckFileExists(this string filename, string paramName = null)
{
CheckNotNull(filename, paramName);
Require<FileNotFoundException>(File.Exists(filename), string.Format("指定的文件路径“{0}”不存在。", filename));
}
}
}
@@ -0,0 +1,86 @@
using CloudBuilder.Core.Application.Builders;
using CloudBuilder.Core.DatabaseAccessor;
using CloudBuilder.Core.DependencyInjection.Form;
using CloudBuilder.Core.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.FileSystemGlobbing;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Reflection;
namespace Microsoft.Extensions.DependencyInjection
{
public static partial class ServiceExtensions
{
/// <summary>
/// 添加依赖注入接口
/// </summary>
/// <param name="services">服务集合</param>
/// <returns>服务集合</returns>
public static IServiceCollection Initialize(this IServiceCollection services)
{
IConfiguration configuration = GetConfiguration();
services.AddSingleton(configuration);
CloudBuilderBuilder builder = new CloudBuilderBuilder(services, configuration);
builder.AddPack();
services.AddSingleton(builder);
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new DefaultContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
return services;
}
public static IServiceProvider Build(this IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();
//初始化WinForm系统环境变量
ApplicationServiceContext applicationServiceContext = serviceProvider.GetService<ApplicationServiceContext>()!;
return serviceProvider;
}
public static IConfiguration GetConfiguration()
{
var entryAssembly = Assembly.GetEntryAssembly();
string localentryAssembly = Path.GetFileNameWithoutExtension(entryAssembly.ManifestModule.Name);
var configuration = new ConfigurationBuilder();
// 获取程序执行目录
var executeDirectory = AppContext.BaseDirectory;
// 获取自定义配置扫描目录
var configurationScanDirectories = (configuration.Build().GetSection("ConfigurationScanDirectories")
.Get<string[]>()
?? Array.Empty<string>()).Select(u => Path.Combine(executeDirectory, u));
// 扫描执行目录及自定义配置目录下的 *.json 文件
var jsonFiles = new[] { executeDirectory }
.Concat(configurationScanDirectories)
.SelectMany(u =>
Directory.GetFiles(u, "*.json", SearchOption.TopDirectoryOnly));
// 如果没有配置文件,中止执行
if (!jsonFiles.Any()) return configuration.Build();
// 循环加载
foreach (var jsonFile in jsonFiles)
{
//存在应用名的不加入
if (Path.GetFileName(jsonFile).Contains(localentryAssembly)) continue;
configuration.AddJsonFile(jsonFile, optional: true, reloadOnChange: true);
}
return configuration.Build();
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// 列表字段排序条件
/// </summary>
public class SortCondition
{
/// <summary>
/// 初始化一个<see cref="SortCondition"/>类型的新实例
/// </summary>
public SortCondition() : this(null)
{ }
/// <summary>
/// 构造一个指定字段名称的升序排序的排序条件
/// </summary>
/// <param name="sortField">字段名称</param>
public SortCondition(string sortField)
: this(sortField, ListSortDirection.Ascending)
{ }
/// <summary>
/// 构造一个排序字段名称和排序方式的排序条件
/// </summary>
/// <param name="sortField">字段名称</param>
/// <param name="listSortDirection">排序方式</param>
public SortCondition(string sortField, ListSortDirection listSortDirection)
{
SortField = sortField;
ListSortDirection = listSortDirection;
}
/// <summary>
/// 获取或设置 排序字段名称
/// </summary>
public string SortField { get; set; }
/// <summary>
/// 获取或设置 排序方向
/// </summary>
public ListSortDirection ListSortDirection { get; set; }
}
/// <summary>
/// 支持泛型的列表字段排序条件
/// </summary>
/// <typeparam name="T">列表元素类型</typeparam>
public class SortCondition<T> : SortCondition
{
/// <summary>
/// 使用排序字段 初始化一个<see cref="SortCondition"/>类型的新实例
/// </summary>
public SortCondition(Expression<Func<T, object>> keySelector)
: this(keySelector, ListSortDirection.Ascending)
{ }
/// <summary>
/// 使用排序字段与排序方式 初始化一个<see cref="SortCondition"/>类型的新实例
/// </summary>
public SortCondition(Expression<Func<T, object>> keySelector, ListSortDirection listSortDirection)
: base(GetPropertyName(keySelector), listSortDirection)
{ }
/// <summary>
/// 从泛型委托获取属性名
/// </summary>
private static string GetPropertyName(Expression<Func<T, object>> keySelector)
{
string param = keySelector.Parameters.First().Name;
string operand = ((dynamic)keySelector.Body).Operand.ToString();
operand = operand.Substring(param.Length + 1, operand.Length - param.Length - 1);
return operand;
}
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,395 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace CloudBuilder.Core.Extensions
{
/// <summary>
/// 类型<see cref="Type"/>辅助扩展方法类
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// 判断当前类型是否可由指定类型派生
/// </summary>
public static bool IsDeriveClassFrom<TBaseType>(this Type type, bool canAbstract = false)
{
return IsDeriveClassFrom(type, typeof(TBaseType), canAbstract);
}
/// <summary>
/// 判断当前类型是否可由指定类型派生
/// </summary>
public static bool IsDeriveClassFrom(this Type type, Type baseType, bool canAbstract = false)
{
return type.IsClass && (canAbstract || !type.IsAbstract) && type.IsBaseOn(baseType);
}
/// <summary>
/// 判断类型是否为Nullable类型
/// </summary>
/// <param name="type"> 要处理的类型 </param>
/// <returns> 是返回True,不是返回False </returns>
public static bool IsNullableType(this Type type)
{
return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
/// <summary>
/// 由类型的Nullable类型返回实际类型
/// </summary>
/// <param name="type"> 要处理的类型对象 </param>
/// <returns> </returns>
public static Type GetNonNullableType(this Type type)
{
return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
}
/// <summary>
/// 通过类型转换器获取Nullable类型的基础类型
/// </summary>
/// <param name="type"> 要处理的类型对象 </param>
/// <returns> </returns>
public static Type GetUnNullableType(this Type type)
{
if (IsNullableType(type))
{
NullableConverter nullableConverter = new NullableConverter(type);
return nullableConverter.UnderlyingType;
}
return type;
}
/// <summary>
/// 获取类型的Description特性描述信息
/// </summary>
/// <param name="type">类型对象</param>
/// <param name="inherit">是否搜索类型的继承链以查找描述特性</param>
/// <returns>返回Description特性描述信息,如不存在则返回类型的全名</returns>
public static string GetDescription(this Type type, bool inherit = true)
{
DescriptionAttribute desc = type.GetAttribute<DescriptionAttribute>(inherit);
return desc == null ? type.FullName : desc.Description;
}
/// <summary>
/// 获取成员元数据的Description特性描述信息
/// </summary>
/// <param name="member">成员元数据对象</param>
/// <param name="inherit">是否搜索成员的继承链以查找描述特性</param>
/// <returns>返回Description特性描述信息,如不存在则返回成员的名称</returns>
public static string GetDescription(this MemberInfo member, bool inherit = true)
{
DescriptionAttribute desc = member.GetAttribute<DescriptionAttribute>(inherit);
if (desc != null)
{
return desc.Description;
}
DisplayNameAttribute displayName = member.GetAttribute<DisplayNameAttribute>(inherit);
if (displayName != null)
{
return displayName.DisplayName;
}
DisplayAttribute display = member.GetAttribute<DisplayAttribute>(inherit);
if (display != null)
{
return display.Name;
}
return member.Name;
}
/// <summary>
/// 检查指定指定类型成员中是否存在指定的Attribute特性
/// </summary>
/// <typeparam name="T">要检查的Attribute特性类型</typeparam>
/// <param name="memberInfo">要检查的类型成员</param>
/// <param name="inherit">是否从继承中查找</param>
/// <returns>是否存在</returns>
public static bool HasAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
{
return memberInfo.IsDefined(typeof(T), inherit);
}
/// <summary>
/// 从类型成员获取指定Attribute特性
/// </summary>
/// <typeparam name="T">Attribute特性类型</typeparam>
/// <param name="memberInfo">类型类型成员</param>
/// <param name="inherit">是否从继承中查找</param>
/// <returns>存在返回第一个,不存在返回null</returns>
public static T GetAttribute<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
{
var attributes = memberInfo.GetCustomAttributes(typeof(T), inherit);
return attributes.FirstOrDefault() as T;
}
/// <summary>
/// 从类型成员获取指定Attribute特性
/// </summary>
/// <typeparam name="T">Attribute特性类型</typeparam>
/// <param name="memberInfo">类型类型成员</param>
/// <param name="inherit">是否从继承中查找</param>
/// <returns>返回所有指定Attribute特性的数组</returns>
public static T[] GetAttributes<T>(this MemberInfo memberInfo, bool inherit = true) where T : Attribute
{
return memberInfo.GetCustomAttributes(typeof(T), inherit).Cast<T>().ToArray();
}
/// <summary>
/// 判断类型是否为集合类型
/// </summary>
/// <param name="type">要处理的类型</param>
/// <returns>是返回True,不是返回False</returns>
public static bool IsEnumerable(this Type type)
{
if (type == typeof(string))
{
return false;
}
return typeof(IEnumerable).IsAssignableFrom(type);
}
/// <summary>
/// 判断当前泛型类型是否可由指定类型的实例填充
/// </summary>
/// <param name="genericType">泛型类型</param>
/// <param name="type">指定类型</param>
/// <returns></returns>
public static bool IsGenericAssignableFrom(this Type genericType, Type type)
{
genericType.CheckNotNull("genericType");
type.CheckNotNull("type");
if (!genericType.IsGenericType)
{
throw new ArgumentException("该功能只支持泛型类型的调用,非泛型类型可使用 IsAssignableFrom 方法。");
}
List<Type> allOthers = new List<Type> { type };
if (genericType.IsInterface)
{
allOthers.AddRange(type.GetInterfaces());
}
foreach (var other in allOthers)
{
Type cur = other;
while (cur != null)
{
if (cur.IsGenericType)
{
cur = cur.GetGenericTypeDefinition();
}
if (cur.IsSubclassOf(genericType) || cur == genericType)
{
return true;
}
cur = cur.BaseType;
}
}
return false;
}
/// <summary>
/// 方法是否是异步
/// </summary>
public static bool IsAsync(this MethodInfo method)
{
return method.ReturnType == typeof(Task)
|| method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>);
}
/// <summary>
/// 返回当前类型是否是指定基类的派生类
/// </summary>
/// <param name="type">当前类型</param>
/// <param name="baseType">要判断的基类型</param>
/// <returns></returns>
public static bool IsBaseOn(this Type type, Type baseType)
{
if (baseType.IsGenericTypeDefinition)
{
return baseType.IsGenericAssignableFrom(type);
}
return baseType.IsAssignableFrom(type);
}
/// <summary>
/// 返回当前类型是否是指定基类的派生类
/// </summary>
/// <typeparam name="TBaseType">要判断的基类型</typeparam>
/// <param name="type">当前类型</param>
/// <returns></returns>
public static bool IsBaseOn<TBaseType>(this Type type)
{
Type baseType = typeof(TBaseType);
return type.IsBaseOn(baseType);
}
/// <summary>
/// 返回当前方法信息是否是重写方法
/// </summary>
/// <param name="method">要判断的方法信息</param>
/// <returns>是否是重写方法</returns>
public static bool IsOverridden(this MethodInfo method)
{
return method.GetBaseDefinition().DeclaringType != method.DeclaringType;
}
/// <summary>
/// 返回当前属性信息是否为virtual
/// </summary>
public static bool IsVirtual(this PropertyInfo property)
{
var accessor = property.GetAccessors().FirstOrDefault();
if (accessor == null)
{
return false;
}
return accessor.IsVirtual && !accessor.IsFinal;
}
/// <summary>
/// 获取类型的全名,附带所在类库
/// </summary>
public static string GetFullNameWithModule(this Type type)
{
return $"{type.FullName},{type.Module.Name.Replace(".dll", "").Replace(".exe", "")}";
}
/// <summary>
/// 获取类型的显示短名称
/// </summary>
public static string ShortDisplayName(this Type type)
{
return type.DisplayName(false);
}
/// <summary>
/// 获取类型的显示名称
/// </summary>
public static string DisplayName([NotNull] this Type type, bool fullName = true)
{
StringBuilder sb = new StringBuilder();
ProcessType(sb, type, fullName);
return sb.ToString();
}
#region 私有方法
private static readonly Dictionary<Type, string> _builtInTypeNames = new Dictionary<Type, string>
{
{ typeof(bool), "bool" },
{ typeof(byte), "byte" },
{ typeof(char), "char" },
{ typeof(decimal), "decimal" },
{ typeof(double), "double" },
{ typeof(float), "float" },
{ typeof(int), "int" },
{ typeof(long), "long" },
{ typeof(object), "object" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(string), "string" },
{ typeof(uint), "uint" },
{ typeof(ulong), "ulong" },
{ typeof(ushort), "ushort" },
{ typeof(void), "void" }
};
private static void ProcessType(StringBuilder builder, Type type, bool fullName)
{
if (type.IsGenericType)
{
var genericArguments = type.GetGenericArguments();
ProcessGenericType(builder, type, genericArguments, genericArguments.Length, fullName);
}
else if (type.IsArray)
{
ProcessArrayType(builder, type, fullName);
}
else if (_builtInTypeNames.TryGetValue(type, out var builtInName))
{
builder.Append(builtInName);
}
else if (!type.IsGenericParameter)
{
builder.Append(fullName ? type.FullName : type.Name);
}
}
private static void ProcessArrayType(StringBuilder builder, Type type, bool fullName)
{
var innerType = type;
while (innerType.IsArray)
{
innerType = innerType.GetElementType();
}
ProcessType(builder, innerType, fullName);
while (type.IsArray)
{
builder.Append('[');
builder.Append(',', type.GetArrayRank() - 1);
builder.Append(']');
type = type.GetElementType();
}
}
private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, bool fullName)
{
var offset = type.IsNested ? type.DeclaringType.GetGenericArguments().Length : 0;
if (fullName)
{
if (type.IsNested)
{
ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, fullName);
builder.Append('+');
}
else
{
builder.Append(type.Namespace);
builder.Append('.');
}
}
var genericPartIndex = type.Name.IndexOf('`');
if (genericPartIndex <= 0)
{
builder.Append(type.Name);
return;
}
builder.Append(type.Name, 0, genericPartIndex);
builder.Append('<');
for (var i = offset; i < length; i++)
{
ProcessType(builder, genericArguments[i], fullName);
if (i + 1 == length)
{
continue;
}
builder.Append(',');
if (!genericArguments[i + 1].IsGenericParameter)
{
builder.Append(' ');
}
}
builder.Append('>');
}
#endregion
}
}