9 Commits

11 changed files with 135 additions and 105 deletions

View File

@ -1,27 +1,27 @@
# ns-ext # ns-ext
[](README.zh-CN.md) | **En** [](README.zh-CN.md) | **En**
The **ns-ext** is a .NET extension function library, containing the following types of extension modules: The **ns-ext** is a .NET extension function library, containing the following types of extension modules:
| Features | File name |
| Features | File name | |------------------------------------------|------------------------------------|
| -------- | ---------------------------------- | | Byte type extension | ByteExtensions.cs |
| Byte type extension | ByteExtensions.cs | | Character Type Extensions | CharExtensions.cs |
| Character Type Extensions | CharExtensions.cs | | Date Type Extensions | DateTimeExtensions.cs |
| Date Type Extensions | DateTimeExtensions.cs | | Database command type extension | DbCommandExtensions.cs |
| Database command type extension | DbCommandExtensions.cs | | Decimal Number Type extension | DecimalExtensions.cs |
| Decimal Number Type extension | DecimalExtensions.cs | | Enumable type extension | EnumerableExtensions.cs |
| Enumable type extension | EnumerableExtensions.cs | | Enumeration type extension | EnumExtensions.cs |
| Enumeration type extension | EnumExtensions.cs | | General type extension | GenericExtensions.cs |
| General type extension | GenericExtensions.cs | | Integer type extension | IntExtensions.cs |
| Integer type extension | IntExtensions.cs |
| Json Serialization option type extension | JsonSerializerOptionsExtensions.cs | | Json Serialization option type extension | JsonSerializerOptionsExtensions.cs |
| Log type extension | LoggerExtensions.cs | | Log type extension | LoggerExtensions.cs |
| Long integer extension | LongExtensions.cs | | Long integer extension | LongExtensions.cs |
| Object type extension | ObjectExtensions.cs | | Object type extension | ObjectExtensions.cs |
| Stream type extension | StreamExtensions.cs | | Stream type extension | StreamExtensions.cs |
| String type extension | StringExtensions.cs | | String type extension | StringExtensions.cs |
| Prototype type extension | TypeExtensions.cs | | Prototype type extension | TypeExtensions.cs |
| Resource locator type extension | UriExtensions.cs | | Resource locator type extension | UriExtensions.cs |
## Quick start ## Quick start

View File

@ -1,25 +0,0 @@
Param(
# Nuget APIKey
[string] $apikey
)
if ($apikey -eq $null -or $apikey -eq "")
{
Write-Error "require apiKey";
return;
}
rm -r ./build/nupkgs
dotnet build -c Release
$files = Get-ChildItem -Path ./build/nupkgs/ -Filter *.nupkg
foreach ($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
nuget add $file.fullName -source d:\nuget-pkg
}
$files = Get-ChildItem -Path ./build/nupkgs/ -Filter *.snupkg
foreach ($file in $files)
{
dotnet nuget push $file.fullName --skip-duplicate --api-key $apikey --source https://api.nuget.org/v3/index.json
nuget add $file.fullName -source d:\nuget-pkg
}

View File

@ -0,0 +1,24 @@
namespace NSExt.Attributes;
/// <summary>
/// 指定本地化资源类型
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Field)]
public class LocalizationAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="LocalizationAttribute" /> class.
/// </summary>
public LocalizationAttribute(Type resourceClass)
{
ResourceClass = resourceClass;
}
/// <summary>
/// Gets or sets 资源类型
/// </summary>
/// <value>
/// 资源类型
/// </value>
public Type ResourceClass { get; set; }
}

19
src/Constant/Regexes.cs Normal file
View File

@ -0,0 +1,19 @@
namespace NSExt.Constant;
#pragma warning disable SYSLIB1045
// 使用 RegexGenerator 新特性会生成重复key值的xmlcomment导致出错
internal static class Regexes
{
public static readonly Regex RegexBacksLantUnicode
= new("\\\\u([a-fA-F0-9]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexHtmlTag = new("<[^>]*>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexMobile
= new("^(\\d{3})\\d{4}(\\d{4})$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexPercentUnicode
= new("\\\\u([a-fA-F0-9]{4})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex RegexUpLetter = new("([A-Z])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
}

View File

@ -42,17 +42,20 @@ public static class ByteExtensions
/// <param name="me">me</param> /// <param name="me">me</param>
/// <param name="upperCase">是否大写</param> /// <param name="upperCase">是否大写</param>
/// <param name="splitShar">字节间分隔符</param> /// <param name="splitShar">字节间分隔符</param>
public static string String(this byte[] me, bool upperCase = true, string splitShar = null) /// <param name="splitInterval">分隔符跳跃字节数</param>
public static string String(this IEnumerable<byte> me, bool upperCase = true, string splitShar = ""
, int splitInterval = 1)
{ {
var ret = BitConverter.ToString(me); var sb = new StringBuilder();
if (!upperCase) { var i = 0;
ret = ret.ToLower(CultureInfo.InvariantCulture); foreach (var c in me.Select(x => x.ToString(upperCase ? "X2" : "x2", CultureInfo.InvariantCulture))) {
if (i++ % splitInterval == 0) {
sb.Append(splitShar);
}
sb.Append(c);
} }
if (splitShar != "-") { return sb.ToString();
ret = ret.Replace("-", splitShar ?? string.Empty);
}
return ret;
} }
} }

View File

@ -1,7 +1,7 @@
namespace NSExt.Extensions; namespace NSExt.Extensions;
/// <summary> /// <summary>
/// DbCommandExtensions /// DbCommandExtensions
/// </summary> /// </summary>
public static class DbCommandExtensions public static class DbCommandExtensions
{ {
@ -15,30 +15,18 @@ public static class DbCommandExtensions
//应逆向替换,否则由于 多个表的过滤器问题导致替换不完整 如 @TenantId1 @TenantId10 //应逆向替换,否则由于 多个表的过滤器问题导致替换不完整 如 @TenantId1 @TenantId10
for (var i = me.Parameters.Count - 1; i >= 0; i--) { for (var i = me.Parameters.Count - 1; i >= 0; i--) {
#pragma warning disable IDE0072
sql = me.Parameters[i].DbType switch { sql = me.Parameters[i].DbType switch {
#pragma warning restore IDE0072
DbType.String or DbType.DateTime or DbType.Date or DbType.Time or DbType.DateTime2 DbType.String or DbType.DateTime or DbType.Date or DbType.Time or DbType.DateTime2
or DbType.DateTimeOffset or DbType.Guid or DbType.VarNumeric or DbType.AnsiStringFixedLength or DbType.DateTimeOffset or DbType.Guid or DbType.VarNumeric or DbType.AnsiStringFixedLength
or DbType.AnsiString or DbType.StringFixedLength => sql.Replace( // or DbType.AnsiString
me.Parameters[i].ParameterName, "'" + me.Parameters[i].Value + "'") or DbType.StringFixedLength =>
, DbType.Boolean => sql.Replace( // sql.Replace(me.Parameters[i].ParameterName, "'" + me.Parameters[i].Value + "'")
me.Parameters[i].ParameterName , DbType.Boolean => sql.Replace(//
, Convert.ToBoolean(me.Parameters[i].Value, CultureInfo.InvariantCulture) ? "1" : "0") me.Parameters[i].ParameterName
, DbType.Binary => throw new NotImplementedException() , Convert.ToBoolean(me.Parameters[i].Value, CultureInfo.InvariantCulture) ? "1" : "0")
, DbType.Byte => throw new NotImplementedException() , _ => sql.Replace(me.Parameters[i].ParameterName, me.Parameters[i].Value?.ToString())
, DbType.Currency => throw new NotImplementedException()
, DbType.Decimal => throw new NotImplementedException()
, DbType.Double => throw new NotImplementedException()
, DbType.Int16 => throw new NotImplementedException()
, DbType.Int32 => throw new NotImplementedException()
, DbType.Int64 => throw new NotImplementedException()
, DbType.Object => throw new NotImplementedException()
, DbType.SByte => throw new NotImplementedException()
, DbType.Single => throw new NotImplementedException()
, DbType.UInt16 => throw new NotImplementedException()
, DbType.UInt32 => throw new NotImplementedException()
, DbType.UInt64 => throw new NotImplementedException()
, DbType.Xml => throw new NotImplementedException()
, _ => sql.Replace(me.Parameters[i].ParameterName, me.Parameters[i].Value?.ToString())
}; };
} }

View File

@ -1,3 +1,6 @@
using System.Reflection;
using NSExt.Attributes;
namespace NSExt.Extensions; namespace NSExt.Extensions;
/// <summary> /// <summary>
@ -12,9 +15,15 @@ public static class EnumExtensions
/// <returns>description属性</returns> /// <returns>description属性</returns>
public static string Desc(this Enum e) public static string Desc(this Enum e)
{ {
var t = e.GetType(); var t = e.GetType();
var fi = t.GetField(Enum.GetName(t, e)!); var fi = t.GetField(Enum.GetName(t, e)!);
var attrs = (DescriptionAttribute[])fi!.GetCustomAttributes(typeof(DescriptionAttribute), false); var descAttr = fi!.GetCustomAttribute<DescriptionAttribute>(true);
return (attrs.Length != 0 ? attrs[0].Description : Enum.GetName(t, e)) ?? string.Empty; if (descAttr is null) {
return Enum.GetName(t, e);
}
var str = descAttr.Description;
var locAttr = fi!.GetCustomAttribute<LocalizationAttribute>(true);
return locAttr is null ? str : locAttr.ResourceClass.GetProperty(str)?.GetValue(default) as string ?? str;
} }
} }

View File

@ -15,14 +15,12 @@ public static class JsonSerializerOptionsExtensions
public static JsonSerializerOptions NewJsonSerializerOptions(this JsonSerializerOptions _) public static JsonSerializerOptions NewJsonSerializerOptions(this JsonSerializerOptions _)
{ {
return new JsonSerializerOptions { return new JsonSerializerOptions {
ReadCommentHandling = JsonCommentHandling.Skip ReadCommentHandling = JsonCommentHandling.Skip
, AllowTrailingCommas = true , AllowTrailingCommas = true
, DictionaryKeyPolicy = JsonNamingPolicy.CamelCase , DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
, PropertyNamingPolicy = JsonNamingPolicy.CamelCase , PropertyNamingPolicy = JsonNamingPolicy.CamelCase
, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping , Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
, NumberHandling , NumberHandling = JsonNumberHandling.AllowReadingFromString
= JsonNumberHandling.AllowReadingFromString |
JsonNumberHandling.WriteAsString
, PropertyNameCaseInsensitive = true , PropertyNameCaseInsensitive = true
}; };
} }

View File

@ -15,7 +15,19 @@ public static class ObjectExtensions
/// <returns>json文本</returns> /// <returns>json文本</returns>
public static string Json(this object me, bool format = false) public static string Json(this object me, bool format = false)
{ {
return JsonSerializer.Serialize( var defaultOptions = default(JsonSerializerOptions).NewJsonSerializerOptions();
me, new JsonSerializerOptions { WriteIndented = format, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); defaultOptions.WriteIndented = format;
return Json(me, defaultOptions);
}
/// <summary>
/// 将一个对象序列化成json文本
/// </summary>
/// <param name="me">指定对象</param>
/// <param name="options">序列化选项</param>
/// <returns>json文本</returns>
public static string Json(this object me, JsonSerializerOptions options)
{
return JsonSerializer.Serialize(me, options);
} }
} }

View File

@ -4,13 +4,14 @@
#pragma warning disable CA1720 #pragma warning disable CA1720
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
using NSExt.Constant;
namespace NSExt.Extensions; namespace NSExt.Extensions;
/// <summary> /// <summary>
/// StringExtensions /// StringExtensions
/// </summary> /// </summary>
public static partial class StringExtensions public static class StringExtensions
{ {
private static readonly JsonSerializerOptions _defaultJsonSerializerOptions private static readonly JsonSerializerOptions _defaultJsonSerializerOptions
= default(JsonSerializerOptions).NewJsonSerializerOptions(); = default(JsonSerializerOptions).NewJsonSerializerOptions();
@ -369,7 +370,7 @@ public static partial class StringExtensions
/// <returns>掩码后的手机号</returns> /// <returns>掩码后的手机号</returns>
public static string MaskMobile(this string me) public static string MaskMobile(this string me)
{ {
return MyRegex().Replace(me, "$1****$2"); return Regexes.RegexMobile.Replace(me, "$1****$2");
} }
/// <summary> /// <summary>
@ -444,7 +445,7 @@ public static partial class StringExtensions
/// <returns>处理之后的字符串</returns> /// <returns>处理之后的字符串</returns>
public static string RemoveHtmlTag(this string me) public static string RemoveHtmlTag(this string me)
{ {
return MyRegex1().Replace(me, string.Empty); return Regexes.RegexHtmlTag.Replace(me, string.Empty);
} }
/// <summary> /// <summary>
@ -473,7 +474,7 @@ public static partial class StringExtensions
/// </summary> /// </summary>
public static string Snakecase(this string me) public static string Snakecase(this string me)
{ {
return MyRegex2().Replace(me, "-$1").ToLower(CultureInfo.InvariantCulture).TrimStart('-'); return Regexes.RegexUpLetter.Replace(me, "-$1").ToLower(CultureInfo.InvariantCulture).TrimStart('-');
} }
/// <summary> /// <summary>
@ -507,6 +508,16 @@ public static partial class StringExtensions
return ret == me ? ret : ret.TrimSpaces(); return ret == me ? ret : ret.TrimSpaces();
} }
/// <summary>
/// 将\ux0000 、 %u0000 、 &amp;#x0000; 编码转换成可读字符串
/// </summary>
public static string UnicodeDe(this string me)
{
const string replacement = "&#x$1;";
return me.Contains(@"\u") ? Regexes.RegexBacksLantUnicode.Replace(me, replacement).HtmlDe() :
me.Contains(@"%u") ? Regexes.RegexPercentUnicode.Replace(me, replacement).HtmlDe() : me.HtmlDe();
}
/// <summary> /// <summary>
/// url编码 /// url编码
/// </summary> /// </summary>
@ -541,13 +552,4 @@ public static partial class StringExtensions
.Replace("-", string.Empty) .Replace("-", string.Empty)
.ToLower(CultureInfo.CurrentCulture); .ToLower(CultureInfo.CurrentCulture);
} }
[GeneratedRegex("^(\\d{3})\\d{4}(\\d{4})$")]
private static partial Regex MyRegex();
[GeneratedRegex("<[^>]*>")]
private static partial Regex MyRegex1();
[GeneratedRegex("([A-Z])")]
private static partial Regex MyRegex2();
} }

View File

@ -1,17 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0</TargetFrameworks> <TargetFramework>net7.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0"/> <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="MinVer" Version="4.3.0-beta.1"> <PackageReference Include="MinVer" Version="4.3.0-beta.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<Import Project="../CodeQuality.props"/> <Import Project="../CodeQuality.props" />
</Project> </Project>