ow
This commit is contained in:
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
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user