├── README.md ├── MrHuo.Extensions ├── MrHuo.Extensions.snk ├── ObjectFormatter │ ├── ObjectDisplayExtensions.cs │ ├── ObjectDisplayOptions.cs │ ├── ObjectFormatter.cs │ ├── CommonPrimitiveFormatterOptions.cs │ ├── CSharpObjectFormatter.cs │ ├── GeneratedNameKindExtensions.cs │ ├── CSharpObjectFormatterImpl.cs │ ├── StringExtensions.cs │ ├── GeneratedNameKind.cs │ ├── SpecialType.cs │ ├── CSharpTypeNameFormatter.cs │ ├── ObjectFormatterHelpers.cs │ ├── CSharpPrimitiveFormatter.cs │ ├── CommonPrimitiveFormatter.cs │ ├── CommonTypeNameFormatter.cs │ ├── ObjectDisplay.cs │ ├── GeneratedNames.cs │ └── CommonObjectFormatter.cs ├── Extensions │ ├── ICollectionExtensions.cs │ ├── ExceptionExtensions.cs │ ├── TimeSpanExtensions.cs │ ├── NameValueCollectionExtensions.cs │ ├── DateTimeExtensions.cs │ ├── ByteExtensions.cs │ ├── CharExtensions.cs │ ├── NumberExtensions.cs │ ├── StreamExtensions.cs │ ├── ReflectExtensions.cs │ ├── ObjectExtensions.cs │ ├── IEnumerableExtensions.cs │ ├── DictionaryExtensions.cs │ └── ConvertExtensions.cs ├── Properties │ └── PublishProfiles │ │ └── FolderProfile.pubxml ├── MrHuo.Extensions.csproj ├── DataTableHelper.cs ├── CookieWebClient.cs ├── Ensure.cs ├── Encrypt │ ├── AES.cs │ └── DES.cs ├── CsvHelper.cs ├── RandomHelper.cs ├── HttpClientHelper.cs └── ExcelHelper.cs ├── LICENSE.txt ├── MrHuo.Extensions.Test ├── MrHuo.Extensions.Test.csproj ├── CsvHelperTest.cs ├── StreamExtensionsTest.cs ├── IEnumerableExtensionsTest.cs ├── HttpClientHelperTest.cs ├── ExcelHelperTest.cs └── StringExtensionsTest.cs ├── MrHuo.Extensions.sln ├── .gitattributes └── .gitignore /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrhuo/MrHuo.Extensions/HEAD/README.md -------------------------------------------------------------------------------- /MrHuo.Extensions/MrHuo.Extensions.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrhuo/MrHuo.Extensions/HEAD/MrHuo.Extensions/MrHuo.Extensions.snk -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/ObjectDisplayExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | internal static class ObjectDisplayExtensions 4 | { 5 | internal static bool IncludesOption( 6 | this ObjectDisplayOptions options, 7 | ObjectDisplayOptions flag) 8 | { 9 | return (options & flag) == flag; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/ObjectDisplayOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MrHuo.Extensions 4 | { 5 | [Flags] 6 | internal enum ObjectDisplayOptions 7 | { 8 | None = 0, 9 | IncludeCodePoints = 1, 10 | IncludeTypeSuffix = 2, 11 | UseHexadecimalNumbers = 4, 12 | UseQuotes = 8, 13 | EscapeNonPrintableCharacters = 16, // 0x00000010 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/ObjectFormatter.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | /// 4 | /// 任意对象格式化工具 5 | /// Code from Microsoft.CodeAnalysis.Scripting 6 | /// 7 | public abstract class ObjectFormatter 8 | { 9 | public static ObjectFormatter Instance = CSharpObjectFormatter.Instance; 10 | public abstract string FormatObject(object obj); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CommonPrimitiveFormatterOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace MrHuo.Extensions 4 | { 5 | internal class CommonPrimitiveFormatterOptions 6 | { 7 | public bool IncludeCharacterCodePoints { get; } 8 | 9 | public bool QuoteStringsAndCharacters { get; } = true; 10 | 11 | public bool EscapeNonPrintableCharacters { get; } = false; 12 | 13 | public CultureInfo CultureInfo { get; } = CultureInfo.CurrentUICulture; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ICollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | /// 7 | /// ICollection 扩展方法 8 | /// 9 | public static class ICollectionExtensions 10 | { 11 | /// 12 | /// 判断一个集合是否有元素 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static bool HasValue(this ICollection value) 18 | { 19 | return value.Any(); 20 | } 21 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | Any CPU 10 | netstandard2.0 11 | bin\Debug\netstandard2.0\publish\ 12 | 13 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CSharpObjectFormatter.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | internal sealed class CSharpObjectFormatter : ObjectFormatter 4 | { 5 | private static readonly ObjectFormatter s_impl = new CSharpObjectFormatterImpl(); 6 | 7 | public static CSharpObjectFormatter Instance { get; } = new CSharpObjectFormatter(); 8 | 9 | private CSharpObjectFormatter() 10 | { 11 | } 12 | 13 | public override string FormatObject(object obj) 14 | { 15 | return CSharpObjectFormatter.s_impl.FormatObject(obj); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright [MrHuo.Extensions] [https://github.com/mrhuo] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/MrHuo.Extensions.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/GeneratedNameKindExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | internal static class GeneratedNameKindExtensions 4 | { 5 | internal static bool IsTypeName(this GeneratedNameKind kind) 6 | { 7 | switch (kind) 8 | { 9 | case GeneratedNameKind.LambdaDisplayClass: 10 | case GeneratedNameKind.StateMachineType: 11 | case GeneratedNameKind.DynamicCallSiteContainerType: 12 | return true; 13 | default: 14 | return false; 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | /// 6 | /// Exception 类扩展方法 7 | /// 8 | public static class ExceptionExtensions 9 | { 10 | /// 11 | /// 获取最顶层的异常信息 12 | /// 13 | /// 14 | /// 15 | public static Exception GetTopException(this Exception ex) 16 | { 17 | if (ex == null) 18 | { 19 | return ex; 20 | } 21 | if (ex.InnerException == null) 22 | { 23 | return ex; 24 | } 25 | return GetTopException(ex.InnerException); 26 | } 27 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/TimeSpanExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | public static class TimeSpanExtensions 6 | { 7 | public static string FormatTime(this TimeSpan timeSpan) 8 | { 9 | var ms = timeSpan.TotalMilliseconds; 10 | if (ms < 1000) 11 | { 12 | return timeSpan.TotalMilliseconds.ToString("F2") + "毫秒"; 13 | } 14 | if (ms < 1000 * 60) 15 | { 16 | return timeSpan.TotalSeconds.ToString("F2") + "秒"; 17 | } 18 | if (ms < 1000 * 60 * 60) 19 | { 20 | return timeSpan.TotalMinutes.ToString("F2") + "分钟"; 21 | } 22 | return timeSpan.TotalHours.ToString("F2") + "小时"; 23 | } 24 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CSharpObjectFormatterImpl.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | internal class CSharpObjectFormatterImpl : CommonObjectFormatter 4 | { 5 | protected override CommonTypeNameFormatter TypeNameFormatter { get; } 6 | 7 | protected override CommonPrimitiveFormatter PrimitiveFormatter { get; } 8 | 9 | internal CSharpObjectFormatterImpl() 10 | { 11 | this.PrimitiveFormatter = new CSharpPrimitiveFormatter(); 12 | this.TypeNameFormatter = new CSharpTypeNameFormatter(this.PrimitiveFormatter); 13 | } 14 | 15 | protected override string FormatRefKind(System.Reflection.ParameterInfo parameter) 16 | { 17 | return !parameter.IsOut ? "ref" : "out"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/NameValueCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.Text; 5 | 6 | /// 7 | /// NameValueCollection 扩展方法 8 | /// 9 | public static class NameValueCollectionExtensions 10 | { 11 | /// 12 | /// 将一个 NameValueCollection 转化成字典 13 | /// 14 | /// 15 | /// 16 | public static Dictionary ToDictionary(this NameValueCollection nameValueCollection) 17 | { 18 | var dict = new Dictionary(); 19 | foreach (var key in nameValueCollection.AllKeys) 20 | { 21 | dict[key] = nameValueCollection[key]; 22 | } 23 | return dict; 24 | } 25 | } -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/CsvHelperTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace MrHuo.Extensions.Test 6 | { 7 | public class CsvHelperTest 8 | { 9 | [Test] 10 | public void TestCsvImport() 11 | { 12 | var csvFile = "E:\\test.csv"; 13 | var i = 0; 14 | var list = CsvHelper.Import(csvFile, new List<(string PropertyName, int? ColumnIndex, Func ValueProceed)>() 15 | { 16 | ("Index", null, data=> ++i), 17 | ("姓名", 0, null), 18 | ("年龄", 1, null), 19 | ("性别", 2, null), 20 | ("生日", 3, null) 21 | }); 22 | } 23 | } 24 | 25 | class Student 26 | { 27 | public int Index { get; set; } 28 | public string 姓名 { get; set; } 29 | public int 年龄 { get; set; } 30 | public string 性别 { get; set; } 31 | public DateTime 生日 { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/StreamExtensionsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace Test 8 | { 9 | public class StreamExtensionsTest 10 | { 11 | [Test] 12 | public void TestStreamToFile() 13 | { 14 | ("HelloWorld" + DateTime.Now.Ticks).ToFile(Path.GetTempFileName()); 15 | var file = Path.GetTempFileName(); 16 | ("HelloWorld" + DateTime.Now.Ticks).AppendToFile(file); 17 | ("HelloWorld" + DateTime.Now.Ticks).AppendToFile(file); 18 | 19 | Assert.Pass(); 20 | } 21 | 22 | [Test] 23 | public void TestStreamToImage() 24 | { 25 | var fromFile = Path.Combine(Path.GetTempPath(), "my.png"); 26 | var stream = fromFile.ToStream(); 27 | var image = stream.ToImage(Path.GetTempFileName(), System.Drawing.Imaging.ImageFormat.Png); 28 | //fromFile.CopyFileTo(Path.GetTempFileName()); 29 | Assert.Pass(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace MrHuo.Extensions 5 | { 6 | internal static class StringExtensions 7 | { 8 | private static readonly Func s_toLower = new Func(char.ToLower); 9 | private static readonly Func s_toUpper = new Func(char.ToUpper); 10 | 11 | internal static string GetNumeral(int number) 12 | { 13 | return $"{number}"; 14 | } 15 | 16 | internal static int IndexOfBalancedParenthesis( 17 | this string str, 18 | int openingOffset, 19 | char closing) 20 | { 21 | char ch1 = str[openingOffset]; 22 | int num = 1; 23 | for (int index = openingOffset + 1; index < str.Length; ++index) 24 | { 25 | char ch2 = str[index]; 26 | if (ch2 == ch1) 27 | ++num; 28 | else if (ch2 == closing) 29 | { 30 | --num; 31 | if (num == 0) 32 | return index; 33 | } 34 | } 35 | return -1; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/IEnumerableExtensionsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | 6 | namespace Tests 7 | { 8 | public class IEnumerableExtensionsTest 9 | { 10 | class StudentModel 11 | { 12 | public string UserName { get; set; } 13 | public string UserPassword { get; set; } 14 | public int UserAge { get; set; } 15 | } 16 | 17 | [Test] 18 | public void TestToExcelFile() 19 | { 20 | var testData = new List(); 21 | for (int i = 0; i < 12; i++) 22 | { 23 | testData.Add(new StudentModel() 24 | { 25 | UserAge = i * 2, 26 | UserName = "Name" + i, 27 | UserPassword = "Password" + i 28 | }); 29 | } 30 | var file = testData.ToExcelFile(new Dictionary>() 31 | { 32 | ["年龄"] = (m) => m.UserAge, 33 | ["名字"] = (m) => m.UserName, 34 | ["密码"] = (m) => m.UserPassword 35 | }); 36 | Assert.Pass(file); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MrHuo.Extensions/MrHuo.Extensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | http://github.com/mrhuo 6 | 非常好用的扩展方法类库,大大提高开发效率和代码质量。 7 | http://github.com/mrhuo 8 | https://github.com/mrhuo/MrHuo.Extensions 9 | LICENSE.txt 10 | https://github.com/mrhuo/MrHuo.Extensions 11 | Github 12 | true 13 | 霍小平 14 | true 15 | MrHuo.Extensions.snk 16 | false 17 | Extensions 18 | 非常好用的扩展方法类库,大大提高开发效率和代码质量。 19 | true 20 | 1.0.2 21 | 1.0.2.0 22 | 1.0.2.0 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/DateTimeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | /// 6 | /// DateTime 扩展方法 7 | /// 8 | public static class DateTimeExtensions 9 | { 10 | #region [ToUnixTime] 11 | /// 12 | /// 将时间转化为Unix时间戳 13 | /// 14 | /// 15 | /// 16 | public static long ToUnixTime(this DateTime dateTime) 17 | { 18 | TimeSpan ts = dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0); 19 | return (long)(ts.TotalSeconds); 20 | } 21 | #endregion 22 | 23 | #region [ToDateTime] 24 | /// 25 | /// Unix时间戳转化为C#时间格式 26 | /// 27 | /// 28 | /// 29 | public static DateTime ToDateTime(this long unixTime) 30 | { 31 | DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); 32 | long lTime = long.Parse(unixTime + "0000"); 33 | TimeSpan toNow = new TimeSpan(lTime); 34 | return dtStart.Add(toNow); 35 | } 36 | #endregion 37 | 38 | #region [Format] 39 | /// 40 | /// 格式化日期 41 | /// 42 | /// 43 | /// 44 | /// 45 | public static string Format(this DateTime dateTime, string formatStr = "yyyy-MM-dd HH:mm:ss") 46 | { 47 | return dateTime.ToString(formatStr); 48 | } 49 | #endregion 50 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ByteExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | 6 | /// 7 | /// Byte 扩展方法 8 | /// 9 | public static class ByteExtensions 10 | { 11 | /// 12 | /// 转化成字符串,默认 UTF8 编码 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static string ToStringEx(this byte[] bytes, Encoding encoding = null) 18 | { 19 | encoding = encoding ?? Encoding.UTF8; 20 | return encoding.GetString(bytes); 21 | } 22 | 23 | /// 24 | /// 转化成16进制的字符串 25 | /// 26 | /// 27 | /// 28 | public static string ToHex(this byte[] bytes) 29 | { 30 | var sb = new StringBuilder(); 31 | foreach (var item in bytes) 32 | { 33 | sb.Append(item.ToString("x2")); 34 | } 35 | return sb.ToString(); 36 | } 37 | 38 | /// 39 | /// 将字节数组写入到文件 40 | /// 41 | /// 42 | /// 43 | public static void ToFile(this byte[] bytes, string fileName) 44 | { 45 | using (var ms = new MemoryStream(bytes)) 46 | { 47 | ms.ToFile(fileName); 48 | } 49 | } 50 | 51 | /// 52 | /// 将字节数组追加到文件,如果不存在,文件自动创建 53 | /// 54 | /// 55 | /// 56 | public static void AppendToFile(this byte[] bytes, string fileName) 57 | { 58 | using (var ms = new MemoryStream(bytes)) 59 | { 60 | ms.AppendToFile(fileName); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/CharExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | /// 4 | /// Char 扩展方法 5 | /// 6 | public static class CharExtensions 7 | { 8 | /// 9 | /// 小写转大写 10 | /// 11 | /// 12 | /// 13 | public static char ToUpper(this char ch) 14 | { 15 | if (ch.IsLower()) 16 | { 17 | ch = (char)(ch - 32); 18 | } 19 | return ch; 20 | } 21 | 22 | /// 23 | /// 大写转小写 24 | /// 25 | /// 26 | /// 27 | public static char ToLower(this char ch) 28 | { 29 | if (ch.IsUpper()) 30 | { 31 | ch = (char)(ch + 32); 32 | } 33 | return ch; 34 | } 35 | 36 | #region [IsUpper] 37 | /// 38 | /// 某个字符是否大写 39 | /// 40 | /// 41 | /// 42 | public static bool IsUpper(this char ch) 43 | { 44 | return ch >= 65 && ch <= 65 + 26; 45 | } 46 | #endregion 47 | 48 | #region [IsLower] 49 | /// 50 | /// 某个字符是否小写 51 | /// 52 | /// 字符 53 | /// 54 | public static bool IsLower(this char ch) 55 | { 56 | return ch >= 97 && ch <= 97 + 26; 57 | } 58 | #endregion 59 | 60 | #region [ToString] 61 | /// 62 | /// 转化成拼接后的字符串 63 | /// 64 | /// 65 | /// 66 | /// 67 | public static string ToString(this IEnumerable enumerable, string separator) 68 | { 69 | return string.Join(separator, enumerable.ToArray()); 70 | } 71 | #endregion 72 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/GeneratedNameKind.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MrHuo.Extensions 4 | { 5 | internal enum GeneratedNameKind 6 | { 7 | None = 0, 8 | StateMachineStateField = 49, // 0x00000031 9 | IteratorCurrentBackingField = 50, // 0x00000032 10 | StateMachineParameterProxyField = 51, // 0x00000033 11 | ThisProxyField = 52, // 0x00000034 12 | HoistedLocalField = 53, // 0x00000035 13 | [Obsolete] Deprecated_OuterscopeLocals = 54, // 0x00000036 14 | ReusableHoistedLocalField = 55, // 0x00000037 15 | DisplayClassLocalOrField = 56, // 0x00000038 16 | LambdaCacheField = 57, // 0x00000039 17 | [Obsolete] Deprecated_IteratorInstance = 97, // 0x00000061 18 | LambdaMethod = 98, // 0x00000062 19 | LambdaDisplayClass = 99, // 0x00000063 20 | StateMachineType = 100, // 0x00000064 21 | FixedBufferField = 101, // 0x00000065 22 | AnonymousType = 102, // 0x00000066 23 | [Obsolete] Deprecated_InitializerLocal = 103, // 0x00000067 24 | LocalFunction = 103, // 0x00000067 25 | TransparentIdentifier = 104, // 0x00000068 26 | AnonymousTypeField = 105, // 0x00000069 27 | [Obsolete] Deprecated_AnonymousTypeTypeParameter = 106, // 0x0000006A 28 | AutoPropertyBackingField = 107, // 0x0000006B 29 | IteratorCurrentThreadIdField = 108, // 0x0000006C 30 | IteratorFinallyMethod = 109, // 0x0000006D 31 | BaseMethodWrapper = 110, // 0x0000006E 32 | DynamicCallSiteContainerType = 111, // 0x0000006F 33 | DynamicCallSiteField = 112, // 0x00000070 34 | [Obsolete] Deprecated_DynamicDelegate = 113, // 0x00000071 35 | [Obsolete] Deprecated_ComrefCallLocal = 114, // 0x00000072 36 | HoistedSynthesizedLocalField = 115, // 0x00000073 37 | AsyncBuilderField = 116, // 0x00000074 38 | AwaiterField = 117, // 0x00000075 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/NumberExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | public static class NumberExtensions 6 | { 7 | #region [FormatMemorySize] 8 | /// 9 | /// 获取友好的格式化后的内存大小表示字符串 10 | /// 11 | /// 12 | /// 13 | public static string GetFriendlyMemorySize(double sizeInBytes) 14 | { 15 | var num = sizeInBytes; 16 | var strArray = new string[5] { "B", "KB", "MB", "GB", "TB" }; 17 | int index; 18 | for (index = 0; num >= 1024.0 && index < strArray.Length - 1; num /= 1024.0) 19 | ++index; 20 | return string.Format(string.Format("{0:0.00} {1}", num, strArray[index])); 21 | } 22 | 23 | /// 24 | /// 获取友好的格式化后的内存大小表示字符串 25 | /// 26 | /// 27 | /// 28 | public static string FormatMemorySize(this int value) 29 | { 30 | return GetFriendlyMemorySize(value); 31 | } 32 | 33 | /// 34 | /// 获取友好的格式化后的内存大小表示字符串 35 | /// 36 | /// 37 | /// 38 | public static string FormatMemorySize(this long value) 39 | { 40 | return GetFriendlyMemorySize(value); 41 | } 42 | 43 | /// 44 | /// 获取友好的格式化后的内存大小表示字符串 45 | /// 46 | /// 47 | /// 48 | public static string FormatMemorySize(this double value) 49 | { 50 | return GetFriendlyMemorySize(value); 51 | } 52 | 53 | /// 54 | /// 获取友好的格式化后的内存大小表示字符串 55 | /// 56 | /// 57 | /// 58 | public static string FormatMemorySize(this float value) 59 | { 60 | return GetFriendlyMemorySize(value); 61 | } 62 | #endregion 63 | } -------------------------------------------------------------------------------- /MrHuo.Extensions.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.902 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MrHuo.Extensions", "MrHuo.Extensions\MrHuo.Extensions.csproj", "{926EA498-F7A4-46CD-A6A4-55202EB41A94}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MrHuo.Extensions.Test", "MrHuo.Extensions.Test\MrHuo.Extensions.Test.csproj", "{7D1AE4B1-60DD-42D6-B25C-5CE3A994D5C2}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "其他", "其他", "{C708F22E-E61C-4135-BCE7-5BCCD9A0C64E}" 11 | ProjectSection(SolutionItems) = preProject 12 | LICENSE.txt = LICENSE.txt 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {926EA498-F7A4-46CD-A6A4-55202EB41A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {926EA498-F7A4-46CD-A6A4-55202EB41A94}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {926EA498-F7A4-46CD-A6A4-55202EB41A94}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {926EA498-F7A4-46CD-A6A4-55202EB41A94}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {7D1AE4B1-60DD-42D6-B25C-5CE3A994D5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {7D1AE4B1-60DD-42D6-B25C-5CE3A994D5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {7D1AE4B1-60DD-42D6-B25C-5CE3A994D5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {7D1AE4B1-60DD-42D6-B25C-5CE3A994D5C2}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {8A00DD2F-D280-494B-8CDE-4F90882C6D57} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/SpecialType.cs: -------------------------------------------------------------------------------- 1 | namespace MrHuo.Extensions 2 | { 3 | internal enum SpecialType : sbyte 4 | { 5 | None = 0, 6 | System_Object = 1, 7 | System_Enum = 2, 8 | System_MulticastDelegate = 3, 9 | System_Delegate = 4, 10 | System_ValueType = 5, 11 | System_Void = 6, 12 | System_Boolean = 7, 13 | System_Char = 8, 14 | System_SByte = 9, 15 | System_Byte = 10, // 0x0A 16 | System_Int16 = 11, // 0x0B 17 | System_UInt16 = 12, // 0x0C 18 | System_Int32 = 13, // 0x0D 19 | System_UInt32 = 14, // 0x0E 20 | System_Int64 = 15, // 0x0F 21 | System_UInt64 = 16, // 0x10 22 | System_Decimal = 17, // 0x11 23 | System_Single = 18, // 0x12 24 | System_Double = 19, // 0x13 25 | System_String = 20, // 0x14 26 | System_IntPtr = 21, // 0x15 27 | System_UIntPtr = 22, // 0x16 28 | System_Array = 23, // 0x17 29 | System_Collections_IEnumerable = 24, // 0x18 30 | System_Collections_Generic_IEnumerable_T = 25, // 0x19 31 | System_Collections_Generic_IList_T = 26, // 0x1A 32 | System_Collections_Generic_ICollection_T = 27, // 0x1B 33 | System_Collections_IEnumerator = 28, // 0x1C 34 | System_Collections_Generic_IEnumerator_T = 29, // 0x1D 35 | System_Collections_Generic_IReadOnlyList_T = 30, // 0x1E 36 | System_Collections_Generic_IReadOnlyCollection_T = 31, // 0x1F 37 | System_Nullable_T = 32, // 0x20 38 | System_DateTime = 33, // 0x21 39 | System_Runtime_CompilerServices_IsVolatile = 34, // 0x22 40 | System_IDisposable = 35, // 0x23 41 | System_TypedReference = 36, // 0x24 42 | System_ArgIterator = 37, // 0x25 43 | System_RuntimeArgumentHandle = 38, // 0x26 44 | System_RuntimeFieldHandle = 39, // 0x27 45 | System_RuntimeMethodHandle = 40, // 0x28 46 | System_RuntimeTypeHandle = 41, // 0x29 47 | System_IAsyncResult = 42, // 0x2A 48 | Count = 43, // 0x2B 49 | System_AsyncCallback = 43, // 0x2B 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/HttpClientHelperTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Diagnostics; 3 | 4 | namespace Test 5 | { 6 | public class HttpClientHelperTest 7 | { 8 | class RestResult 9 | { 10 | } 11 | 12 | [Test] 13 | public void TestWebClientGet() 14 | { 15 | Debug.WriteLine("http://www.baidu.com".HttpGet()); 16 | var ex = Assert.Catch(() => 17 | { 18 | "http://www.fwerwrxfwer.com".HttpGet(true); 19 | }); 20 | Debug.WriteLine(ex.ToString()); 21 | 22 | var html = "http://www.example.com".HttpPost(new System.Collections.Generic.Dictionary() 23 | { 24 | ["userId"] = "xxx", 25 | ["userName"] = "xxx" 26 | }); 27 | var restResult = "http://www.example.com".HttpPost(new System.Collections.Generic.Dictionary() 28 | { 29 | ["userId"] = "xxx", 30 | ["userName"] = "xxx" 31 | }); 32 | Assert.Pass(); 33 | } 34 | 35 | [Test] 36 | public void HttpClientGet() 37 | { 38 | var result = "http://whois.pconline.com.cn/ip.jsp?ip={ip}".HttpGet(); 39 | Debug.WriteLine(result); 40 | 41 | Debug.WriteLine("http://www.baidu.com".HttpGet()); 42 | var ex = Assert.Catch(() => 43 | { 44 | "http://www.fwerwrxfwer.com".HttpGet(true); 45 | }); 46 | Debug.WriteLine(ex.ToString()); 47 | 48 | var html = "http://www.example.com".HttpPost(new System.Collections.Generic.Dictionary() 49 | { 50 | ["userId"] = "xxx", 51 | ["userName"] = "xxx" 52 | }); 53 | var restResult = "http://www.example.com".HttpPost(new System.Collections.Generic.Dictionary() 54 | { 55 | ["userId"] = "xxx", 56 | ["userName"] = "xxx" 57 | }); 58 | Assert.Pass(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MrHuo.Extensions/DataTableHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Text; 5 | 6 | namespace MrHuo.Extensions 7 | { 8 | /// 9 | /// DataTable 帮助类 10 | /// 11 | public static class DataTableHelper 12 | { 13 | /// 14 | /// 将一个 IEnumerable 对象转换到 DataTable 15 | /// 16 | /// 任意类型 17 | /// IEnumerable 对象 18 | /// 列定义,默认为 null,通过反射的方式确定列名 19 | /// 表名,默认为null,取 nameof(T) 20 | /// 21 | public static DataTable IEnumerableToDataTable(IEnumerable data, Dictionary> columnDef = null, string tableName = null) 22 | { 23 | Ensure.NotNull(data); 24 | var dataTable = new DataTable(tableName ?? typeof(T).Name); 25 | if (columnDef == null) 26 | { 27 | var properties = typeof(T).GetProperties(); 28 | foreach (var item in properties) 29 | { 30 | dataTable.Columns.Add(new DataColumn(item.Name)); 31 | } 32 | foreach (var row in data) 33 | { 34 | var dr = dataTable.NewRow(); 35 | foreach (var col in properties) 36 | { 37 | dr[col.Name] = col.GetValue(row); 38 | } 39 | dataTable.Rows.Add(dr); 40 | } 41 | } 42 | else 43 | { 44 | foreach (var item in columnDef) 45 | { 46 | dataTable.Columns.Add(new DataColumn(item.Key)); 47 | } 48 | foreach (var row in data) 49 | { 50 | var dr = dataTable.NewRow(); 51 | foreach (var col in columnDef) 52 | { 53 | dr[col.Key] = col.Value(row); 54 | } 55 | dataTable.Rows.Add(dr); 56 | } 57 | } 58 | return dataTable; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MrHuo.Extensions/CookieWebClient.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net; 3 | using System.Net.Http; 4 | 5 | namespace MrHuo.Extensions 6 | { 7 | /// 8 | /// 带 Cookies 请求的 WebClient 9 | /// 10 | public class CookieWebClient : WebClient 11 | { 12 | private CookieContainer cookieContainer = new CookieContainer(); 13 | 14 | /// 15 | /// 获取最后访问的 URL 16 | /// 17 | public string Referer { get; set; } 18 | 19 | /// 20 | /// 清空 Cookies 21 | /// 22 | public CookieWebClient ClearCookies() 23 | { 24 | cookieContainer = new CookieContainer(); 25 | return this; 26 | } 27 | 28 | /// 29 | /// 手动添加 Cookies 30 | /// 31 | /// 32 | /// 33 | public CookieWebClient AddCookies(Dictionary cookies) 34 | { 35 | foreach (var item in cookies) 36 | { 37 | cookieContainer.Add(new Cookie(item.Key, item.Value)); 38 | } 39 | return this; 40 | } 41 | 42 | /// 43 | /// 手动添加 Cookies 44 | /// 45 | /// 46 | /// 47 | public CookieWebClient AddCookies(List cookies) 48 | { 49 | foreach (var item in cookies) 50 | { 51 | cookieContainer.Add(item); 52 | } 53 | return this; 54 | } 55 | 56 | /// 57 | /// 重写请求,加入 Cookies 58 | /// 59 | /// 60 | /// 61 | protected override WebRequest GetWebRequest(System.Uri address) 62 | { 63 | var request = base.GetWebRequest(address); 64 | if (request is HttpWebRequest) 65 | { 66 | var httpWebRequest = (HttpWebRequest)request; 67 | httpWebRequest.CookieContainer = cookieContainer; 68 | if (Referer != null) 69 | { 70 | httpWebRequest.Referer = Referer; 71 | } 72 | } 73 | Referer = address.ToString(); 74 | return request; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CSharpTypeNameFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MrHuo.Extensions 4 | { 5 | internal class CSharpTypeNameFormatter : CommonTypeNameFormatter 6 | { 7 | protected override CommonPrimitiveFormatter PrimitiveFormatter { get; } 8 | 9 | public CSharpTypeNameFormatter(CommonPrimitiveFormatter primitiveFormatter) 10 | { 11 | this.PrimitiveFormatter = primitiveFormatter; 12 | } 13 | 14 | protected override string GenericParameterOpening 15 | { 16 | get 17 | { 18 | return "<"; 19 | } 20 | } 21 | 22 | protected override string GenericParameterClosing 23 | { 24 | get 25 | { 26 | return ">"; 27 | } 28 | } 29 | 30 | protected override string ArrayOpening 31 | { 32 | get 33 | { 34 | return "["; 35 | } 36 | } 37 | 38 | protected override string ArrayClosing 39 | { 40 | get 41 | { 42 | return "]"; 43 | } 44 | } 45 | 46 | protected override string GetPrimitiveTypeName(SpecialType type) 47 | { 48 | switch (type) 49 | { 50 | case SpecialType.System_Object: 51 | return "object"; 52 | case SpecialType.System_Boolean: 53 | return "bool"; 54 | case SpecialType.System_Char: 55 | return "char"; 56 | case SpecialType.System_SByte: 57 | return "sbyte"; 58 | case SpecialType.System_Byte: 59 | return "byte"; 60 | case SpecialType.System_Int16: 61 | return "short"; 62 | case SpecialType.System_UInt16: 63 | return "ushort"; 64 | case SpecialType.System_Int32: 65 | return "int"; 66 | case SpecialType.System_UInt32: 67 | return "uint"; 68 | case SpecialType.System_Int64: 69 | return "long"; 70 | case SpecialType.System_UInt64: 71 | return "ulong"; 72 | case SpecialType.System_Decimal: 73 | return "decimal"; 74 | case SpecialType.System_Single: 75 | return "float"; 76 | case SpecialType.System_Double: 77 | return "double"; 78 | case SpecialType.System_String: 79 | return "string"; 80 | default: 81 | return null; 82 | } 83 | } 84 | 85 | public override string FormatTypeName(Type type) 86 | { 87 | string methodName; 88 | if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(type.Name, GeneratedNameKind.StateMachineType, out methodName)) 89 | return methodName; 90 | return base.FormatTypeName(type); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Ensure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | /// 7 | /// 检查输入参数 8 | /// 9 | internal static class Ensure 10 | { 11 | /// 12 | /// 检查输入参数是否为 null,如为 null,则抛出 ArgumentNullException 异常 13 | /// 14 | /// 任意对象 15 | /// 对象参数名,默认为 nameof(obj) 16 | /// 17 | public static void NotNull(object obj, string paramName = null) 18 | { 19 | paramName = paramName ?? nameof(obj); 20 | if (obj == null) 21 | { 22 | throw new ArgumentNullException(paramName); 23 | } 24 | } 25 | 26 | /// 27 | /// 检查输入字符串是否为 null 或为空字符串,如为空,则抛出 ArgumentNullException 异常 28 | /// 29 | /// 任意字符串 30 | /// 对象参数名,默认为 nameof(str) 31 | /// 32 | public static void NotNullOrEmpty(string str, string paramName = null) 33 | { 34 | paramName = paramName ?? nameof(str); 35 | if (string.IsNullOrEmpty(str)) 36 | { 37 | throw new ArgumentNullException(paramName); 38 | } 39 | } 40 | 41 | /// 42 | /// 检查输入的文件路径是否存在,如不存在,则抛出 FileNotFoundException 异常 43 | /// 44 | /// 文件路径 45 | /// 46 | public static void FileExists(string filePath) 47 | { 48 | if (!File.Exists(filePath)) 49 | { 50 | throw new FileNotFoundException($"文件[{filePath}]不存在", filePath); 51 | } 52 | } 53 | 54 | /// 55 | /// 检查输入的文件的扩展名 56 | /// 57 | /// 58 | /// 59 | public static void FileExtensions(string filePath, params string[] extensions) 60 | { 61 | if (!string.IsNullOrEmpty(filePath) && extensions.Length > 0) 62 | { 63 | var ext = Path.GetExtension(filePath).ToLower(); 64 | if (!extensions.Any(p => ext == p)) 65 | { 66 | throw new NotSupportedException($"不支持的扩展名为[{ext}]的文件,允许的扩展名为[{extensions.Join(",")}]"); 67 | } 68 | } 69 | } 70 | 71 | /// 72 | /// 检查输入的文件夹路径是否存在,如不存在,则抛出 DirectoryNotFoundException 异常 73 | /// 74 | /// 文件夹路径 75 | /// 76 | public static void DirectoryExist(string dirPath) 77 | { 78 | if (!Directory.Exists(dirPath)) 79 | { 80 | throw new DirectoryNotFoundException($"文件夹[{dirPath}]不存在"); 81 | } 82 | } 83 | 84 | /// 85 | /// 检查输入的集合 Count 是否等于0,如等于0,则抛出 Exception 异常 86 | /// 87 | /// 88 | /// 89 | public static void HasValue(ICollection collection) 90 | { 91 | if (collection.Count == 0) 92 | { 93 | throw new Exception($"集合内没有数据"); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Encrypt/AES.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | 7 | namespace MrHuo.Extensions 8 | { 9 | /// 10 | /// AES 加密 11 | /// 12 | public static class AES 13 | { 14 | /// 15 | /// 加密 16 | /// 17 | /// 18 | /// 19 | /// 20 | public static string Encrypt(string input, string key) 21 | { 22 | var encryptKey = Encoding.UTF8.GetBytes(key); 23 | using (var aesAlg = Aes.Create()) 24 | { 25 | using (var encryptor = aesAlg.CreateEncryptor(encryptKey, aesAlg.IV)) 26 | { 27 | using (var msEncrypt = new MemoryStream()) 28 | { 29 | using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) 30 | using (var swEncrypt = new StreamWriter(csEncrypt)) 31 | { 32 | swEncrypt.Write(input); 33 | } 34 | var iv = aesAlg.IV; 35 | var decryptedContent = msEncrypt.ToArray(); 36 | var result = new byte[iv.Length + decryptedContent.Length]; 37 | 38 | Buffer.BlockCopy(iv, 0, result, 0, iv.Length); 39 | Buffer.BlockCopy(decryptedContent, 0, result, 40 | iv.Length, decryptedContent.Length); 41 | 42 | return Convert.ToBase64String(result); 43 | } 44 | } 45 | } 46 | } 47 | 48 | /// 49 | /// 解密 50 | /// 51 | /// 52 | /// 53 | /// 54 | public static string Decrypt(string input, string key) 55 | { 56 | var fullCipher = Convert.FromBase64String(input); 57 | 58 | var iv = new byte[16]; 59 | var cipher = new byte[fullCipher.Length - iv.Length]; 60 | 61 | Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length); 62 | Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, fullCipher.Length - iv.Length); 63 | var decryptKey = Encoding.UTF8.GetBytes(key); 64 | 65 | using (var aesAlg = Aes.Create()) 66 | { 67 | using (var decryptor = aesAlg.CreateDecryptor(decryptKey, iv)) 68 | { 69 | string result; 70 | using (var msDecrypt = new MemoryStream(cipher)) 71 | { 72 | using (var csDecrypt = new CryptoStream(msDecrypt, 73 | decryptor, CryptoStreamMode.Read)) 74 | { 75 | using (var srDecrypt = new StreamReader(csDecrypt)) 76 | { 77 | result = srDecrypt.ReadToEnd(); 78 | } 79 | } 80 | } 81 | 82 | return result; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /MrHuo.Extensions/CsvHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MrHuo.Extensions 7 | { 8 | /// 9 | /// CSV 帮助类 10 | /// 11 | public static class CsvHelper 12 | { 13 | /// 14 | /// 从 CSV 文件中导入数据 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// 22 | public static List Import( 23 | string csvFile, 24 | List<(string PropertyName, int? ColumnIndex, Func ValueProceed)> columnsDef, 25 | bool includeTitleRow = true, 26 | int titleRowNum = 1) 27 | where T : new() 28 | { 29 | Ensure.NotNull(csvFile); 30 | Ensure.FileExists(csvFile); 31 | Ensure.NotNull(columnsDef); 32 | var ret = new List(); 33 | var lines = csvFile.ReadFileAllLines(); 34 | if (lines.Count == 0) 35 | { 36 | return ret; 37 | } 38 | var firstLine = lines.FirstOrDefault(); 39 | var maxColumns = firstLine.Split(',').Length; 40 | 41 | var startLine = 0; 42 | if (includeTitleRow && titleRowNum > 0) 43 | { 44 | startLine = startLine + titleRowNum; 45 | } 46 | foreach (var line in lines.Skip(startLine)) 47 | { 48 | var lineData = line.Split(','); 49 | var dataItem = new T(); 50 | var hasError = false; 51 | 52 | foreach (var def in columnsDef) 53 | { 54 | var property = dataItem.GetProperty(def.PropertyName); 55 | if (property == null) 56 | { 57 | continue; 58 | } 59 | try 60 | { 61 | object data = null; 62 | if (def.ColumnIndex == null) 63 | { 64 | if (def.ValueProceed != null) 65 | { 66 | data = def.ValueProceed(data); 67 | } 68 | } 69 | else 70 | { 71 | if (def.ColumnIndex.Value <= maxColumns - 1) 72 | { 73 | var value = lineData[def.ColumnIndex.Value]; 74 | if (!string.IsNullOrEmpty(value)) 75 | { 76 | data = ((object)value).To(property.PropertyType); 77 | if (def.ValueProceed != null) 78 | { 79 | data = def.ValueProceed(data); 80 | } 81 | } 82 | } 83 | } 84 | dataItem.SetValue(def.PropertyName, data); 85 | } 86 | catch (Exception ex) 87 | { 88 | Console.WriteLine("EXCEPTION: " + ex.ToString()); 89 | hasError = true; 90 | } 91 | } 92 | if (!hasError) 93 | { 94 | ret.Add(dataItem); 95 | } 96 | } 97 | return ret; 98 | } 99 | 100 | //TODO: 101 | //ExportDataTable() 102 | //ExportIEnumerable() 103 | //ExportJsonFile() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Text; 7 | 8 | /// 9 | /// Stream 扩展方法 10 | /// 11 | public static class StreamExtensions 12 | { 13 | /// 14 | /// 使用读取流的方式打开文件,并返回 FileStream 15 | /// 16 | /// 17 | /// 18 | public static FileStream GetReadStream(this string filePath) 19 | { 20 | return new FileStream(filePath, FileMode.Open, FileAccess.Read); 21 | } 22 | 23 | /// 24 | /// 使用写入流的方式打开文件,并返回 FileStream 25 | /// 26 | /// 27 | /// 28 | public static FileStream GetWriteStream(this string filePath) 29 | { 30 | return new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write); 31 | } 32 | 33 | /// 34 | /// 使用追加流的方式打开文件,并返回 FileStream 35 | /// 36 | /// 37 | /// 38 | public static FileStream GetAppendStream(this string filePath) 39 | { 40 | return new FileStream(filePath, FileMode.Append, FileAccess.Write); 41 | } 42 | 43 | /// 44 | /// 将可读的 Stream 写入到文件中 45 | /// 46 | /// 可读 Stream 47 | /// 需要写入的文件路径 48 | /// Stream不可读或写入文件有问题会抛出异常 49 | public static void ToFile(this Stream stream, string fileName) 50 | { 51 | if (!stream.CanRead) 52 | { 53 | throw new IOException("该Stream不可读"); 54 | } 55 | using (var fileStream = fileName.GetWriteStream()) 56 | { 57 | var bytes = new byte[stream.Length]; 58 | stream.Read(bytes, 0, bytes.Length); 59 | stream.Seek(0, SeekOrigin.Begin); 60 | using (var binaryWriter = new BinaryWriter(fileStream)) 61 | { 62 | binaryWriter.Write(bytes); 63 | binaryWriter.Close(); 64 | fileStream.Close(); 65 | } 66 | } 67 | } 68 | 69 | /// 70 | /// 将可读的 Stream 追加到文件,如果不存在,文件自动创建 71 | /// 72 | /// 可读 Stream 73 | /// 需要写入的文件路径 74 | public static void AppendToFile(this Stream stream, string fileName) 75 | { 76 | if (!stream.CanRead) 77 | { 78 | throw new IOException("该Stream不可读"); 79 | } 80 | using (var fileStream = fileName.GetAppendStream()) 81 | { 82 | var bytes = new byte[stream.Length]; 83 | stream.Read(bytes, 0, bytes.Length); 84 | stream.Seek(0, SeekOrigin.Begin); 85 | using (var binaryWriter = new BinaryWriter(fileStream)) 86 | { 87 | binaryWriter.Write(bytes); 88 | binaryWriter.Close(); 89 | fileStream.Close(); 90 | } 91 | } 92 | } 93 | 94 | /// 95 | /// 写入图片 Stream 到一个文件,默认格式为 ImageFormat.Jpeg 96 | /// 97 | /// 可读 Stream 98 | /// 需要写入的文件路径 99 | public static Image ToImage(this Stream stream, string fileName) 100 | { 101 | return ToImage(stream, fileName, ImageFormat.Jpeg); 102 | } 103 | 104 | /// 105 | /// 写入到一个图片,可传入 ImageFormat 106 | /// 107 | /// 可读 Stream 108 | /// 需要写入的文件路径 109 | /// 图片格式 110 | public static Image ToImage(this Stream stream, string fileName, ImageFormat imageFormat) 111 | { 112 | var image = Image.FromStream(stream); 113 | image.Save(fileName, imageFormat); 114 | return image; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ReflectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | /// 6 | /// 反射扩展方法 7 | /// 8 | public static class ReflectExtensions 9 | { 10 | /// 11 | /// 判断某个 ICustomAttributeProvider 对象实例是否具有 TAttribute 类型的特性 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static bool HasAttribute(this ICustomAttributeProvider provider, bool inherit = false) 18 | where TAttribute : Attribute 19 | { 20 | var attrs = provider.GetAttributes(inherit); 21 | return attrs != null && attrs.Length > 0; 22 | } 23 | 24 | /// 25 | /// 获取某个 ICustomAttributeProvider 对象实例的所有 TAttribute 类型的特性 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | public static TAttribute[] GetAttributes(this ICustomAttributeProvider provider, bool inherit = false) 32 | where TAttribute : Attribute 33 | { 34 | return provider.GetCustomAttributes(typeof(TAttribute), inherit) as TAttribute[]; 35 | } 36 | 37 | /// 38 | /// 获取元素具有的指定特性 39 | /// 40 | /// 41 | /// 42 | /// 43 | /// 44 | public static TAttribute GetAttribute(this ICustomAttributeProvider provider, bool inherit = false) 45 | where TAttribute : Attribute 46 | { 47 | return provider.GetAttributes(inherit)?.FirstOrDefault(); 48 | } 49 | 50 | /// 51 | /// 将一个对象的每一个公开可读属性调用委托处理 52 | /// 53 | /// 54 | /// 55 | public static void EveryPropertyInvoke(this T obj, Action propertyAction) 56 | where T : class 57 | { 58 | if (propertyAction == null) 59 | { 60 | return; 61 | } 62 | var allProperties = obj.GetType().GetProperties(); 63 | foreach (var item in allProperties) 64 | { 65 | if (item.CanRead) 66 | { 67 | var value = item.GetValue(obj); 68 | propertyAction(item, value); 69 | } 70 | } 71 | } 72 | 73 | /// 74 | /// 直接获取对象的属性 75 | /// 76 | /// 77 | /// 78 | /// 79 | /// 80 | public static PropertyInfo GetProperty(this T obj, string propertyName) 81 | { 82 | return obj.GetType().GetProperty(propertyName); 83 | } 84 | 85 | /// 86 | /// 直接对对象的属性赋值 87 | /// 属性不存在或不可写时,不执行任何操作 88 | /// 89 | /// 90 | /// 91 | /// 92 | /// 93 | public static void SetValue(this T obj, string propertyName, object data) 94 | { 95 | var property = obj.GetProperty(propertyName); 96 | if (property != null && property.CanWrite) 97 | { 98 | property.SetValue(obj, data); 99 | } 100 | } 101 | 102 | /// 103 | /// 直接获取对象属性的值 104 | /// 属性不存在或不可读,返回 null 105 | /// 106 | /// 107 | /// 108 | /// 109 | /// 110 | public static object GetValue(this T obj, string propertyName) 111 | { 112 | var property = obj.GetProperty(propertyName); 113 | if (property == null || !property.CanRead) 114 | { 115 | return null; 116 | } 117 | return property.GetValue(obj); 118 | } 119 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/ObjectFormatterHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace MrHuo.Extensions 7 | { 8 | internal static class ObjectFormatterHelpers 9 | { 10 | internal static readonly object VoidValue = new object(); 11 | 12 | internal static bool HasOverriddenToString(System.Reflection.TypeInfo type) 13 | { 14 | if (type.IsInterface) 15 | return false; 16 | for (; type.AsType() != (object)typeof(object); type = IntrospectionExtensions.GetTypeInfo(type.BaseType)) 17 | { 18 | if ((object)type.GetDeclaredMethod("ToString") != null) 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | internal static object GetMemberValue(MemberInfo member, object obj, out Exception exception) 25 | { 26 | exception = null; 27 | try 28 | { 29 | if (member is FieldInfo fieldInfo) 30 | return fieldInfo.GetValue(obj); 31 | if (member is MethodInfo methodInfo) 32 | return methodInfo.ReturnType == (object)typeof(void) ? ObjectFormatterHelpers.VoidValue : methodInfo.Invoke(obj, Array.Empty()); 33 | PropertyInfo propertyInfo = (PropertyInfo)member; 34 | if ((object)propertyInfo.GetMethod == null) 35 | return null; 36 | return propertyInfo.GetValue(obj, Array.Empty()); 37 | } 38 | catch (TargetInvocationException ex) 39 | { 40 | exception = ex.InnerException; 41 | } 42 | return null; 43 | } 44 | 45 | internal static SpecialType GetPrimitiveSpecialType(Type type) 46 | { 47 | if (type == (object)typeof(int)) 48 | return SpecialType.System_Int32; 49 | if (type == (object)typeof(string)) 50 | return SpecialType.System_String; 51 | if (type == (object)typeof(bool)) 52 | return SpecialType.System_Boolean; 53 | if (type == (object)typeof(char)) 54 | return SpecialType.System_Char; 55 | if (type == (object)typeof(long)) 56 | return SpecialType.System_Int64; 57 | if (type == (object)typeof(double)) 58 | return SpecialType.System_Double; 59 | if (type == (object)typeof(byte)) 60 | return SpecialType.System_Byte; 61 | if (type == (object)typeof(Decimal)) 62 | return SpecialType.System_Decimal; 63 | if (type == (object)typeof(uint)) 64 | return SpecialType.System_UInt32; 65 | if (type == (object)typeof(ulong)) 66 | return SpecialType.System_UInt64; 67 | if (type == (object)typeof(float)) 68 | return SpecialType.System_Single; 69 | if (type == (object)typeof(short)) 70 | return SpecialType.System_Int16; 71 | if (type == (object)typeof(ushort)) 72 | return SpecialType.System_UInt16; 73 | if (type == (object)typeof(DateTime)) 74 | return SpecialType.System_DateTime; 75 | if (type == (object)typeof(sbyte)) 76 | return SpecialType.System_SByte; 77 | if (type == (object)typeof(object)) 78 | return SpecialType.System_Object; 79 | return type == (object)typeof(void) ? SpecialType.System_Void : SpecialType.None; 80 | } 81 | 82 | internal static ObjectDisplayOptions GetObjectDisplayOptions( 83 | bool useQuotes = false, 84 | bool escapeNonPrintable = false, 85 | bool includeCodePoints = false) 86 | { 87 | ObjectDisplayOptions objectDisplayOptions = ObjectDisplayOptions.None; 88 | if (useQuotes) 89 | objectDisplayOptions |= ObjectDisplayOptions.UseQuotes; 90 | if (escapeNonPrintable) 91 | objectDisplayOptions |= ObjectDisplayOptions.EscapeNonPrintableCharacters; 92 | if (includeCodePoints) 93 | objectDisplayOptions |= ObjectDisplayOptions.IncludeCodePoints; 94 | return objectDisplayOptions; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/ExcelHelperTest.cs: -------------------------------------------------------------------------------- 1 | using MrHuo.Extensions; 2 | using NUnit.Framework; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Test 8 | { 9 | class TransferTask 10 | { 11 | public string TaskId { get; set; } 12 | public string TaskName { get; set; } 13 | public string From { get; set; } 14 | public string To { get; set; } 15 | public DateTime CreateTime { get; set; } 16 | public bool IsOk { get; set; } 17 | public string TransferDetail { get; set; } 18 | } 19 | public class ExcelHelperTest 20 | { 21 | private List GetTransferTasks() 22 | { 23 | var tasks = new List(); 24 | for (int i = 0; i < 100; i++) 25 | { 26 | tasks.Add(new TransferTask() 27 | { 28 | CreateTime = DateTime.Now, 29 | IsOk = i % 5 == 0, 30 | From = "FromApi_" + i, 31 | To = "ToApi_" + i, 32 | TaskId = Guid.NewGuid().ToString("n"), 33 | TaskName = "Task_" + (i + 1), 34 | TransferDetail = $"Transfer [{"FromApi_" + i}] To [{"ToApi_" + i}] {(i % 5 == 0 ? "成功" : "失败")}" 35 | }); 36 | } 37 | return tasks; 38 | } 39 | 40 | [Test] 41 | public void TestExportDictionary() 42 | { 43 | var transferTaskDict = GetTransferTasks().ToDictionary(p => p.TaskId, p => p); 44 | var fileName = transferTaskDict.ToExcelFile(new Dictionary, object>>() 45 | { 46 | ["时间"] = (item) => item.Value.CreateTime.Format(), 47 | ["任务名"] = (item) => item.Value.TaskName, 48 | ["任务Id"] = (item) => item.Key, 49 | ["是否成功"] = (item) => item.Value.IsOk ? "成功" : "失败", 50 | ["FROM"] = (item) => item.Value.From, 51 | ["TO"] = (item) => item.Value.To, 52 | ["详情"] = (item) => item.Value.TransferDetail 53 | }); 54 | Assert.Pass($"TestExportDictionary: 已导出到【{fileName}】"); 55 | } 56 | 57 | [Test] 58 | public void TestExportDateTable() 59 | { 60 | var transferTaskDataTable = GetTransferTasks().ToDataTable(); 61 | var fileName = MrHuo.Extensions.ExcelHelper.ExportToFile(transferTaskDataTable); 62 | Assert.Pass($"TestExportDateTable: 已导出到【{fileName}】"); 63 | } 64 | 65 | [Test] 66 | public void TestExportDateTable2() 67 | { 68 | var index = 1; 69 | var transferTaskDataTable = GetTransferTasks().ToDataTable(new Dictionary>() 70 | { 71 | ["Id"] = (item) => $"{index++}", 72 | ["时间"] = (item) => item.CreateTime.Format(), 73 | ["任务名"] = (item) => item.TaskName, 74 | ["任务Id"] = (item) => item.TaskId, 75 | ["是否成功"] = (item) => item.IsOk ? "成功" : "失败", 76 | ["FROM"] = (item) => item.From, 77 | ["TO"] = (item) => item.To, 78 | ["详情"] = (item) => item.TransferDetail 79 | }); 80 | var fileName = MrHuo.Extensions.ExcelHelper.ExportToFile(transferTaskDataTable); 81 | Assert.Pass($"TestExportDateTable: 已导出到【{fileName}】"); 82 | } 83 | 84 | [Test] 85 | public void TestImport() 86 | { 87 | var excelFile = "E:\\test.xls"; 88 | var i = 0; 89 | var ret = ExcelHelper.Import(excelFile, new List<(string PropertyName, int? ColumnIndex, Func ValueProceed)>() 90 | { 91 | ("Index", null, data=> ++i), 92 | ("姓名", 0, null), 93 | ("年龄", 1, null), 94 | ("性别", 2, null), 95 | ("生日", null, data=> DateTime.Now), 96 | ("123", null, data=> null) 97 | }); 98 | } 99 | } 100 | 101 | class Student 102 | { 103 | public int Index { get; set; } 104 | public string 姓名 { get; set; } 105 | public int 年龄 { get; set; } 106 | public string 性别 { get; set; } 107 | public DateTime 生日 { get; set; } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using MrHuo.Extensions; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Text; 10 | 11 | /// 12 | /// Object 扩展方法 13 | /// 14 | public static class ObjectExtensions 15 | { 16 | /// 17 | /// 将任意类型对象序列化成 JSON 18 | /// 19 | /// 20 | /// 21 | /// 22 | public static string ToJson(this object obj, Formatting formatting = Formatting.None, JsonSerializerSettings settings = null) 23 | { 24 | return JsonConvert.SerializeObject(obj, formatting, settings ?? new JsonSerializerSettings()); 25 | } 26 | 27 | /// 28 | /// 将一个 JSON 字符串反序列化成对象 29 | /// 30 | /// 31 | /// 32 | /// 33 | /// 34 | public static T FromJson(this string json, JsonSerializerSettings settings = null) 35 | { 36 | return JsonConvert.DeserializeObject(json, settings ?? new JsonSerializerSettings()); 37 | } 38 | 39 | #region [Mapper] 40 | /// 41 | /// 将一个对象映射成为另外一个对象,相同名称的属性自动赋值 42 | /// 43 | /// 44 | /// 45 | /// 46 | public static T MapTo(this object obj) where T : class, new() 47 | { 48 | var allProperties = obj.GetType().GetProperties(); 49 | var destProperties = typeof(T).GetProperties(); 50 | var ret = new T(); 51 | foreach (var item in allProperties) 52 | { 53 | var dest = destProperties.SingleOrDefault(p => p.Name == item.Name); 54 | if (dest != null && item.CanRead && dest.CanWrite && item.PropertyType == dest.PropertyType) 55 | { 56 | var value = item.GetValue(obj, null); 57 | dest.SetValue(ret, value); 58 | } 59 | } 60 | return ret; 61 | } 62 | 63 | /// 64 | /// 使用原对象中的某些属性,生成新对象 65 | /// 66 | /// 任意对象类型 67 | /// 新对象类型 68 | /// 69 | /// 70 | /// 71 | public static TDest MapTo(this TSource obj, Func func) 72 | where TDest: class 73 | { 74 | return func(obj); 75 | } 76 | 77 | /// 78 | /// 对一个列表的多个元素执行 MapTo 操作,返回新的对象 List 79 | /// 80 | /// 81 | /// 82 | /// 83 | /// 84 | /// 85 | public static List MapTo(this IEnumerable sources, Func func) 86 | where TDest: class 87 | { 88 | var list = new List(); 89 | foreach (var item in sources) 90 | { 91 | list.Add(func(item)); 92 | } 93 | return list; 94 | } 95 | #endregion 96 | 97 | #region [Dump] 98 | /// 99 | /// 将对象转化为 String 表示,并写入 Console Window 100 | /// 101 | /// 102 | public static string DumpToConsole(this object obj) 103 | { 104 | var str = DumpToString(obj); 105 | Console.WriteLine(str); 106 | return str; 107 | } 108 | /// 109 | /// 将对象转化为 String 表示,并写入 Debug Window 110 | /// 111 | /// 112 | public static string DumpToDebug(this object obj) 113 | { 114 | var str = DumpToString(obj); 115 | Debug.WriteLine(str); 116 | return str; 117 | } 118 | 119 | private static readonly ObjectFormatter objectFormatter = ObjectFormatter.Instance; 120 | /// 121 | /// 将任意对象转化为 String 表示 122 | /// 123 | /// 124 | /// 125 | public static string DumpToString(this object obj) 126 | { 127 | return objectFormatter.FormatObject(obj); 128 | } 129 | #endregion 130 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CSharpPrimitiveFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | 4 | namespace MrHuo.Extensions 5 | { 6 | internal class CSharpPrimitiveFormatter : CommonPrimitiveFormatter 7 | { 8 | protected override string NullLiteral 9 | { 10 | get 11 | { 12 | return ObjectDisplay.NullLiteral; 13 | } 14 | } 15 | 16 | protected override string FormatLiteral(bool value) 17 | { 18 | return ObjectDisplay.FormatLiteral(value); 19 | } 20 | 21 | protected override string FormatLiteral( 22 | string value, 23 | bool useQuotes, 24 | bool escapeNonPrintable) 25 | { 26 | ObjectDisplayOptions objectDisplayOptions = ObjectFormatterHelpers.GetObjectDisplayOptions(useQuotes, escapeNonPrintable, false); 27 | return ObjectDisplay.FormatLiteral(value, objectDisplayOptions); 28 | } 29 | 30 | protected override string FormatLiteral( 31 | char c, 32 | bool useQuotes, 33 | bool escapeNonPrintable, 34 | bool includeCodePoints = false) 35 | { 36 | ObjectDisplayOptions objectDisplayOptions = ObjectFormatterHelpers.GetObjectDisplayOptions(useQuotes, escapeNonPrintable, includeCodePoints); 37 | return ObjectDisplay.FormatLiteral(c, objectDisplayOptions); 38 | } 39 | 40 | protected override string FormatLiteral(sbyte value, CultureInfo cultureInfo = null) 41 | { 42 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 43 | } 44 | 45 | protected override string FormatLiteral(byte value, CultureInfo cultureInfo = null) 46 | { 47 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 48 | } 49 | 50 | protected override string FormatLiteral(short value, CultureInfo cultureInfo = null) 51 | { 52 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 53 | } 54 | 55 | protected override string FormatLiteral(ushort value, CultureInfo cultureInfo = null) 56 | { 57 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 58 | } 59 | 60 | protected override string FormatLiteral(int value, CultureInfo cultureInfo = null) 61 | { 62 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 63 | } 64 | 65 | protected override string FormatLiteral(uint value, CultureInfo cultureInfo = null) 66 | { 67 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 68 | } 69 | 70 | protected override string FormatLiteral(long value, CultureInfo cultureInfo = null) 71 | { 72 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 73 | } 74 | 75 | protected override string FormatLiteral(ulong value, CultureInfo cultureInfo = null) 76 | { 77 | return ObjectDisplay.FormatLiteral(value, ObjectFormatterHelpers.GetObjectDisplayOptions(false, false, false), cultureInfo); 78 | } 79 | 80 | protected override string FormatLiteral(double value, CultureInfo cultureInfo = null) 81 | { 82 | return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, cultureInfo); 83 | } 84 | 85 | protected override string FormatLiteral(float value, CultureInfo cultureInfo = null) 86 | { 87 | return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, cultureInfo); 88 | } 89 | 90 | protected override string FormatLiteral(Decimal value, CultureInfo cultureInfo = null) 91 | { 92 | return ObjectDisplay.FormatLiteral(value, ObjectDisplayOptions.None, cultureInfo); 93 | } 94 | 95 | protected override string FormatLiteral(DateTime value, CultureInfo cultureInfo = null) 96 | { 97 | return null; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /MrHuo.Extensions/RandomHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace MrHuo.Extensions 7 | { 8 | /// 9 | /// 随机字符串帮助类 10 | /// 11 | public static class RandomHelper 12 | { 13 | /// 14 | /// 26个小写字母 15 | /// 16 | public static readonly string LowercaseString = "abcdefghijklmnopqrstuvwxyz"; 17 | /// 18 | /// 26个大写字母 19 | /// 20 | public static readonly string UppercaseString = LowercaseString.ToUpper(); 21 | /// 22 | /// 10个数字 23 | /// 24 | public static readonly string NumberString = "01234567890"; 25 | 26 | /// 27 | /// 获取随机生成器 28 | /// 29 | /// 30 | private static Random GetRandom() 31 | { 32 | return new Random(Guid.NewGuid().GetHashCode()); 33 | } 34 | 35 | /// 36 | /// 生成指定长度的随机数字字符串 37 | /// 38 | /// 39 | /// 40 | public static string RandomNumberString(int length) 41 | { 42 | return RandomString(length, false, false, true); 43 | } 44 | 45 | /// 46 | /// 随机 bool 47 | /// 48 | /// 49 | public static bool RandomBool() 50 | { 51 | return GetRandom().NextDouble() > 0.5; 52 | } 53 | 54 | /// 55 | /// 生成指定范围内的随机数字 56 | /// 57 | /// 最小值 58 | /// 最大值 59 | /// 60 | public static int RandomNumber(int min, int max) 61 | { 62 | return GetRandom().Next(min, max); 63 | } 64 | 65 | /// 66 | /// 生成随机字符串,包含:小写字母,大写字母,数字,可输入用户字典扩展 67 | /// 默认生成10个随机字符 68 | /// 69 | /// 字符串长度 70 | /// 是否包含小写字母 71 | /// 是否包含大写字母 72 | /// 73 | /// 用户提供的字典 74 | /// 75 | public static string RandomString( 76 | int length = 10, 77 | bool includeLower = true, 78 | bool includeUpper = true, 79 | bool includeNumber = true, 80 | string userDict = "") 81 | { 82 | var str = 83 | $"{(includeLower ? LowercaseString : "")}" + 84 | $"{(includeUpper ? UppercaseString : "")}" + 85 | $"{(includeNumber ? NumberString : "")}" + 86 | $"{userDict}"; 87 | var ret = string.Empty; 88 | for (int i = 0; i < length; i++) 89 | { 90 | ret += str.Random(1).ToString(string.Empty); 91 | } 92 | return ret; 93 | } 94 | 95 | /// 96 | /// 从一个列表中随机获取一个元素 97 | /// 98 | /// 99 | /// 100 | /// 101 | public static T RandomOne(IEnumerable data) 102 | { 103 | if (data == null || !data.Any()) 104 | { 105 | return default(T); 106 | } 107 | return data.OrderBy(p => GetRandom().Next()).FirstOrDefault(); 108 | } 109 | 110 | /// 111 | /// 从一个列表中随机选择某几个元素,如果 take = 0,则返回随机排序的所有元素 112 | /// 113 | /// 114 | /// 115 | /// 116 | /// 117 | public static IEnumerable RandomSome(IEnumerable data, int take = 0) 118 | { 119 | if (data == null || !data.Any()) 120 | { 121 | return data; 122 | } 123 | var ret = data.OrderBy(p => GetRandom().Next()); 124 | if (take>0) 125 | { 126 | return ret.Take(take); 127 | } 128 | return ret; 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CommonPrimitiveFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Reflection; 4 | 5 | namespace MrHuo.Extensions 6 | { 7 | internal abstract class CommonPrimitiveFormatter 8 | { 9 | protected abstract string NullLiteral { get; } 10 | 11 | protected abstract string FormatLiteral(bool value); 12 | 13 | protected abstract string FormatLiteral( 14 | string value, 15 | bool quote, 16 | bool escapeNonPrintable); 17 | 18 | protected abstract string FormatLiteral( 19 | char value, 20 | bool quote, 21 | bool escapeNonPrintable, 22 | bool includeCodePoints = false); 23 | 24 | protected abstract string FormatLiteral(sbyte value, CultureInfo cultureInfo = null); 25 | 26 | protected abstract string FormatLiteral(byte value, CultureInfo cultureInfo = null); 27 | 28 | protected abstract string FormatLiteral(short value, CultureInfo cultureInfo = null); 29 | 30 | protected abstract string FormatLiteral(ushort value, CultureInfo cultureInfo = null); 31 | 32 | protected abstract string FormatLiteral(int value, CultureInfo cultureInfo = null); 33 | 34 | protected abstract string FormatLiteral(uint value, CultureInfo cultureInfo = null); 35 | 36 | protected abstract string FormatLiteral(long value, CultureInfo cultureInfo = null); 37 | 38 | protected abstract string FormatLiteral(ulong value, CultureInfo cultureInfo = null); 39 | 40 | protected abstract string FormatLiteral(double value, CultureInfo cultureInfo = null); 41 | 42 | protected abstract string FormatLiteral(float value, CultureInfo cultureInfo = null); 43 | 44 | protected abstract string FormatLiteral(Decimal value, CultureInfo cultureInfo = null); 45 | 46 | protected abstract string FormatLiteral(DateTime value, CultureInfo cultureInfo = null); 47 | 48 | public string FormatPrimitive(object obj, CommonPrimitiveFormatterOptions options) 49 | { 50 | if (obj == ObjectFormatterHelpers.VoidValue) 51 | return string.Empty; 52 | if (obj == null) 53 | return this.NullLiteral; 54 | Type type = obj.GetType(); 55 | if (IntrospectionExtensions.GetTypeInfo(type).IsEnum) 56 | return obj.ToString(); 57 | switch (ObjectFormatterHelpers.GetPrimitiveSpecialType(type)) 58 | { 59 | case SpecialType.None: 60 | case SpecialType.System_Object: 61 | case SpecialType.System_Void: 62 | return null; 63 | case SpecialType.System_Boolean: 64 | return this.FormatLiteral((bool)obj); 65 | case SpecialType.System_Char: 66 | return this.FormatLiteral((char)obj, options.QuoteStringsAndCharacters, options.EscapeNonPrintableCharacters, options.IncludeCharacterCodePoints); 67 | case SpecialType.System_SByte: 68 | return this.FormatLiteral((sbyte)obj, options.CultureInfo); 69 | case SpecialType.System_Byte: 70 | return this.FormatLiteral((byte)obj, options.CultureInfo); 71 | case SpecialType.System_Int16: 72 | return this.FormatLiteral((short)obj, options.CultureInfo); 73 | case SpecialType.System_UInt16: 74 | return this.FormatLiteral((ushort)obj, options.CultureInfo); 75 | case SpecialType.System_Int32: 76 | return this.FormatLiteral((int)obj, options.CultureInfo); 77 | case SpecialType.System_UInt32: 78 | return this.FormatLiteral((uint)obj, options.CultureInfo); 79 | case SpecialType.System_Int64: 80 | return this.FormatLiteral((long)obj, options.CultureInfo); 81 | case SpecialType.System_UInt64: 82 | return this.FormatLiteral((ulong)obj, options.CultureInfo); 83 | case SpecialType.System_Decimal: 84 | return this.FormatLiteral((Decimal)obj, options.CultureInfo); 85 | case SpecialType.System_Single: 86 | return this.FormatLiteral((float)obj, options.CultureInfo); 87 | case SpecialType.System_Double: 88 | return this.FormatLiteral((double)obj, options.CultureInfo); 89 | case SpecialType.System_String: 90 | return this.FormatLiteral((string)obj, options.QuoteStringsAndCharacters, options.EscapeNonPrintableCharacters); 91 | case SpecialType.System_DateTime: 92 | return this.FormatLiteral((DateTime)obj, options.CultureInfo); 93 | default: 94 | throw new NotSupportedException(ObjectFormatterHelpers.GetPrimitiveSpecialType(type).ToString()); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using MrHuo.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | /// 9 | /// IEnumerable 扩展方法 10 | /// 11 | public static class IEnumerableExtensions 12 | { 13 | #region [ToDataTable] 14 | /// 15 | /// IEnumerable 对象转换到 DataTable 16 | /// 17 | /// 任意类型 18 | /// IEnumerable 对象 19 | /// 列定义,默认为 null,通过反射的方式确定列名 20 | /// 表名,默认为null,取 nameof(T) 21 | /// 22 | public static DataTable ToDataTable(this IEnumerable data, Dictionary> columnDef = null, string tableName = null) 23 | { 24 | return DataTableHelper.IEnumerableToDataTable(data, columnDef, tableName); 25 | } 26 | #endregion 27 | 28 | #region [ToExcel] 29 | /// 30 | /// IEnumerable 对象导出到 Excel 文件 31 | /// 32 | /// 任意类型 33 | /// 34 | /// 列定义,默认为 null,通过反射的方式确定列名 35 | /// Sheet名称,默认 Sheet1 36 | /// Excel 文件路径,默认为空,创建一个临时文件 37 | /// 是否包含标题行,默认为true(包含) 38 | /// 39 | public static string ToExcelFile( 40 | this IEnumerable data, 41 | Dictionary> columnDef = null, 42 | string sheetName = "Sheet1", 43 | string saveFile = null, 44 | bool includeTitleRow = true) 45 | { 46 | return ExcelHelper.ExportToFile(data, columnDef, sheetName, saveFile, includeTitleRow); 47 | } 48 | 49 | /// 50 | /// IEnumerable 对象输出到 Excel 内存流 51 | /// 52 | /// 任意类型 53 | /// IEnumerable 54 | /// 列定义,默认为 null,通过反射的方式确定列名 55 | /// Sheet名称,默认 Sheet1 56 | /// 是否包含标题行,默认为true(包含) 57 | /// 58 | public static MemoryStream ToExcelStream( 59 | this IEnumerable data, 60 | Dictionary> columnDef = null, 61 | string sheetName = "Sheet1", 62 | bool includeTitleRow = true) 63 | { 64 | return ExcelHelper.ExportToMemoryStream(data, columnDef, sheetName, includeTitleRow); 65 | } 66 | #endregion 67 | 68 | #region [Random] 69 | /// 70 | /// 随机排序后选择前 take 个元素,为 0 时返回全部 71 | /// 72 | /// 任意类型 73 | /// 74 | /// 75 | /// 76 | public static IEnumerable Random(this IEnumerable data, int take = 0) 77 | { 78 | return RandomHelper.RandomSome(data, take); 79 | } 80 | 81 | /// 82 | /// 随机返回一个元素 83 | /// 84 | /// 任意类型 85 | /// 86 | /// 87 | /// 88 | public static T Random(this IEnumerable data) 89 | { 90 | return RandomHelper.RandomOne(data); 91 | } 92 | #endregion 93 | 94 | #region [AsArray] 95 | /// 96 | /// 将一个数组转化类型成另外一个类型 97 | /// 此方法会忽略类型转化失败的元素 98 | /// 99 | /// 100 | /// 101 | /// 102 | public static T[] AsArray(this IEnumerable arr) 103 | { 104 | if (arr == null || arr.Count() == 0) 105 | { 106 | return default(T[]); 107 | } 108 | List retArr = new List(); 109 | foreach (var item in arr) 110 | { 111 | try 112 | { 113 | var v = item.To(default(T), false); 114 | retArr.Add(v); 115 | } 116 | catch { } 117 | } 118 | return retArr.ToArray(); 119 | } 120 | #endregion 121 | 122 | #region [Flat] 123 | /// 124 | /// 将一个集合数组展开成一个集合 125 | /// 126 | /// 127 | /// 128 | /// 129 | public static IEnumerable Flat(this IEnumerable> data) 130 | { 131 | var ret = new List(); 132 | foreach (var item1 in data) 133 | { 134 | foreach (var item2 in item1) 135 | { 136 | ret.Add(item2); 137 | } 138 | } 139 | return ret; 140 | } 141 | #endregion 142 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/Encrypt/DES.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace MrHuo.Extensions 9 | { 10 | /// 11 | /// DES 加密/解密 12 | /// 13 | public class DES 14 | { 15 | public static byte[] DefaultIV = Encoding.UTF8.GetBytes($"MrHuo.Extensions"); 16 | /// 17 | /// DES 加密 18 | /// 19 | /// 字符串 20 | /// 密码 21 | /// 加密向量 22 | /// 23 | public string Encrypt(string inputString, byte[] key, byte[] iv) 24 | { 25 | try 26 | { 27 | using (var ms = new MemoryStream()) 28 | { 29 | var des = new DESCryptoServiceProvider(); 30 | using (var cs = new CryptoStream(ms, des.CreateEncryptor(key, iv), CryptoStreamMode.Write)) 31 | { 32 | using (var sw = new StreamWriter(cs)) 33 | { 34 | sw.Write(inputString); 35 | sw.Flush(); 36 | cs.FlushFinalBlock(); 37 | return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length); 38 | } 39 | } 40 | } 41 | } 42 | catch (Exception ex) 43 | { 44 | Debug.WriteLine(ex); 45 | return null; 46 | } 47 | } 48 | 49 | /// 50 | /// DES 加密,密码为字符串 51 | /// 52 | /// 字符串 53 | /// 密码 54 | /// 加密向量 55 | /// 56 | public string Encrypt(string inputString, string key, byte[] iv) 57 | { 58 | if (string.IsNullOrEmpty(inputString)) 59 | { 60 | throw new Exception("需要DES加密的字符串不能为空!"); 61 | } 62 | if (string.IsNullOrEmpty(key)) 63 | { 64 | throw new Exception("DES加密时密码不能为空!"); 65 | } 66 | var keys = key.PadLeft(8, '0').ToBytes().Take(8).ToArray(); 67 | return Encrypt(inputString, keys, iv); 68 | } 69 | 70 | /// 71 | /// DES 加密,密码为字符串,加密向量默认为本类的哈希值 72 | /// 73 | /// 字符串 74 | /// 密码 75 | /// 76 | public string Encrypt(string inputString, string key) 77 | { 78 | return Encrypt(inputString, key, DefaultIV); 79 | } 80 | 81 | /// 82 | /// DES 解密 83 | /// 84 | /// 85 | /// 86 | /// 87 | /// 88 | public string Decrypt(string inputString, byte[] key, byte[] iv) 89 | { 90 | try 91 | { 92 | if (string.IsNullOrEmpty(inputString)) 93 | { 94 | throw new Exception("需要DES解密的字符串不能为空!"); 95 | } 96 | using (var ms = new MemoryStream(Convert.FromBase64String(inputString))) 97 | { 98 | DESCryptoServiceProvider des = new DESCryptoServiceProvider(); 99 | using (var cs = new CryptoStream(ms, des.CreateDecryptor(key, iv), CryptoStreamMode.Read)) 100 | { 101 | using (var sr = new StreamReader(cs)) 102 | { 103 | return sr.ReadToEnd(); 104 | } 105 | } 106 | } 107 | } 108 | catch (Exception ex) 109 | { 110 | Debug.WriteLine(ex); 111 | return null; 112 | } 113 | } 114 | 115 | /// 116 | /// DES 解密,密码为字符串 117 | /// 118 | /// 字符串 119 | /// 密码 120 | /// 加密向量 121 | /// 122 | public string Decrypt(string inputString, string key, byte[] iv) 123 | { 124 | if (string.IsNullOrEmpty(key)) 125 | { 126 | throw new Exception("DES解密时密码不能为空!"); 127 | } 128 | var keys = key.PadLeft(8, '0').ToBytes().Take(8).ToArray(); 129 | return Decrypt(inputString, keys, iv); 130 | } 131 | 132 | /// 133 | /// DES解密。 134 | /// 135 | /// 已加密字符串 136 | /// 密码 137 | /// 解密后的字符串。 138 | public string Decrypt(string inputString, string key) 139 | { 140 | return Decrypt(inputString, key, DefaultIV); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Specialized; 3 | using System.Linq; 4 | 5 | /// 6 | /// 字典扩展方法 7 | /// 8 | public static class DictionaryExtensions 9 | { 10 | #region [Get] 11 | /// 12 | /// 从字典中获取指定 Key 的值,如果 Key 不存在,返回 default(TValue) 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | public static TValue Get( 21 | this Dictionary dictionary, 22 | TKey key, 23 | TValue defaultValue = default(TValue)) 24 | { 25 | if (dictionary.ContainsKey(key)) 26 | { 27 | return dictionary[key]; 28 | } 29 | return defaultValue; 30 | } 31 | 32 | /// 33 | /// 从字典中获取指定索引的值,如果 Key 不存在,返回 default(TValue) 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | public static TValue Get( 42 | this Dictionary dictionary, 43 | int index, 44 | TValue defaultValue = default(TValue)) 45 | { 46 | if (index < 0 || index > dictionary.Count - 1) 47 | { 48 | return defaultValue; 49 | } 50 | var i = 0; 51 | var enumerator = dictionary.GetEnumerator(); 52 | while (enumerator.MoveNext()) 53 | { 54 | if (i++ == index) 55 | { 56 | return enumerator.Current.Value; 57 | } 58 | } 59 | return defaultValue; 60 | } 61 | #endregion 62 | 63 | /// 64 | /// 从字典中移除多个 key,返回移除个数 65 | /// 66 | /// 67 | /// 68 | /// 69 | /// 70 | /// 71 | public static int Remove(this Dictionary dictionary, params TKey[] keys) 72 | { 73 | var removed = 0; 74 | foreach (var key in keys) 75 | { 76 | if (dictionary.ContainsKey(key)) 77 | { 78 | dictionary.Remove(key); 79 | removed++; 80 | } 81 | } 82 | return removed; 83 | } 84 | 85 | /// 86 | /// 获取字典的所有 Key,返回 List 87 | /// 88 | /// 89 | /// 90 | /// 91 | /// 92 | public static List Keys(this Dictionary dictionary) 93 | { 94 | return dictionary.Keys.ToList(); 95 | } 96 | 97 | /// 98 | /// 获取字典的所有 Value,返回 List 99 | /// 100 | /// 101 | /// 102 | /// 103 | /// 104 | public static List Values(this Dictionary dictionary) 105 | { 106 | return dictionary.Values.ToList(); 107 | } 108 | 109 | /// 110 | /// 将一个字典拼接成一个字符串 111 | /// 112 | /// 113 | /// 114 | /// 115 | /// 是每个元素之间的分隔符 116 | /// 是元素键值对之间的分隔符 117 | /// 118 | public static string Join(this Dictionary dictionary, string joinSeparator, string keyValueSeparator) 119 | { 120 | var arr = (from kv in dictionary 121 | select $"{kv.Key}{keyValueSeparator}{kv.Value}").ToArray(); 122 | return string.Join(joinSeparator, arr); 123 | } 124 | 125 | /// 126 | /// 将一个字典转化成 QueryString 字符串 127 | /// 128 | /// 129 | /// 130 | /// 131 | /// 132 | public static string ToQueryString(this Dictionary dictionary, bool urlEncodeValue = true) 133 | { 134 | var arr = (from kv in dictionary 135 | let v = $"{kv.Value}".UrlEncode() 136 | select $"{kv.Key}={kv.Value}").ToArray(); 137 | return string.Join("&", arr); 138 | } 139 | 140 | /// 141 | /// 将一个字典转化成 NameValueCollection 对象 142 | /// 143 | /// 144 | /// 145 | /// 146 | /// 147 | public static NameValueCollection ToNameValueCollection(this Dictionary dictionary) 148 | { 149 | var collection = new NameValueCollection(); 150 | foreach (var item in dictionary) 151 | { 152 | collection.Add($"{item.Key}", $"{item.Value}"); 153 | } 154 | return collection; 155 | } 156 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | #commit bat 264 | commit.bat -------------------------------------------------------------------------------- /MrHuo.Extensions/HttpClientHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Linq; 8 | 9 | namespace MrHuo.Extensions 10 | { 11 | /// 12 | /// HttpClient 帮助类 13 | /// 14 | public static class HttpClientHelper 15 | { 16 | public static Encoding DefaultEncoding = Encoding.UTF8; 17 | 18 | #region [GET] 19 | /// 20 | /// Get 请求,返回字节码 21 | /// 22 | /// 23 | /// 24 | /// 25 | public static (byte[] Data, Exception Error) GetBytes(string api, Dictionary headers = null) 26 | { 27 | using (var client = new WebClient() { Encoding = DefaultEncoding }) 28 | { 29 | try 30 | { 31 | if (headers != null) 32 | { 33 | foreach (var item in headers) 34 | { 35 | client.Headers.Add(item.Key, $"{item.Value}"); 36 | } 37 | } 38 | return (client.DownloadData(api), null); 39 | } 40 | catch (Exception ex) 41 | { 42 | return (null, ex); 43 | } 44 | } 45 | } 46 | 47 | /// 48 | /// GET 请求,返回网页内容 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | public static (string Data, Exception Error) Get(string api, Dictionary headers = null, Encoding encoding = null) 55 | { 56 | var (Data, Error) = GetBytes(api, headers); 57 | if (Error != null) 58 | { 59 | return (null, Error); 60 | } 61 | return (Data.ToStringEx(encoding), null); 62 | } 63 | 64 | /// 65 | /// GET 请求(反序列化成对象) 66 | /// 67 | /// 68 | /// 69 | /// 70 | /// 71 | /// 72 | public static (T Data, Exception Error) Get(string api, Dictionary headers = null, Encoding encoding = null) 73 | { 74 | var (Data, Error) = Get(api, headers, encoding); 75 | if (Error != null) 76 | { 77 | return (default(T), Error); 78 | } 79 | return (Data.FromJson(), null); 80 | } 81 | #endregion 82 | 83 | #region [POST] 84 | /// 85 | /// POST 请求,返回网页内容 86 | /// 87 | /// 88 | /// 89 | /// 90 | /// 91 | /// 92 | public static (byte[] Data, Exception Error) PostBytes(string api, Dictionary data = null, Dictionary headers = null) 93 | { 94 | data = data ?? new Dictionary(); 95 | using (var client = new WebClient() { Encoding = DefaultEncoding }) 96 | { 97 | try 98 | { 99 | if (headers != null) 100 | { 101 | foreach (var item in headers) 102 | { 103 | client.Headers.Add(item.Key, $"{item.Value}"); 104 | } 105 | } 106 | return (client.UploadValues(api, data.ToNameValueCollection()), null); 107 | } 108 | catch (Exception ex) 109 | { 110 | return (null, ex); 111 | } 112 | } 113 | } 114 | 115 | /// 116 | /// POST 请求,返回网页内容 117 | /// 118 | /// 119 | /// 120 | /// 121 | /// 122 | /// 123 | public static (string Data, Exception Error) Post(string api, Dictionary data = null, Dictionary headers = null, Encoding encoding = null) 124 | { 125 | var (Data, Error) = PostBytes(api, data, headers); 126 | if (Error != null) 127 | { 128 | return (null, Error); 129 | } 130 | return (Data.ToStringEx(encoding), null); 131 | } 132 | 133 | /// 134 | /// POST 请求(反序列化成对象) 135 | /// 136 | /// 137 | /// 138 | /// 139 | /// 140 | /// 141 | public static (T Data, Exception Error) Post(string api, Dictionary data = null, Dictionary headers = null, Encoding encoding = null) 142 | { 143 | var (Data, Error) = Post(api, data, headers, encoding); 144 | if (Error != null) 145 | { 146 | return (default(T), Error); 147 | } 148 | return (Data.FromJson(), null); 149 | } 150 | #endregion 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /MrHuo.Extensions/Extensions/ConvertExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | /// 7 | /// 类型转换相关的扩展方法 8 | /// 9 | public static class ConvertExtensions 10 | { 11 | #region [GetDefaultValueOfType] 12 | /// 13 | /// 获取指定类型的默认值 14 | /// 15 | /// 16 | /// 17 | public static object GetDefaultValueOfType(this Type type) 18 | { 19 | return type.IsValueType ? Activator.CreateInstance(type) : null; 20 | } 21 | #endregion 22 | 23 | #region [To] 24 | /// 25 | /// 将一个值转换为任意类型 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | public static object To(this object value, Type targetType, bool throwException = false) 32 | { 33 | try 34 | { 35 | var valueString = value.ToString(); 36 | if (targetType.IsEnum == true) 37 | { 38 | var result = Enum.Parse(targetType, valueString, true); 39 | return result; 40 | } 41 | var convertible = value as IConvertible; 42 | if (convertible != null) 43 | { 44 | if (typeof(IConvertible).IsAssignableFrom(targetType) == true) 45 | { 46 | var result = convertible.ToType(targetType, null); 47 | return result; 48 | } 49 | //判断convertsionType是否为nullable泛型类 50 | else if (targetType.IsGenericType && 51 | targetType.GetGenericTypeDefinition() == typeof(Nullable<>)) 52 | { 53 | return Convert.ChangeType(convertible, Nullable.GetUnderlyingType(targetType)); 54 | } 55 | } 56 | if (typeof(Guid) == targetType) 57 | { 58 | var result = Guid.Parse(valueString); 59 | return result; 60 | } 61 | else if (typeof(string) == targetType) 62 | { 63 | var result = valueString; 64 | return true; 65 | } 66 | return null; 67 | } 68 | catch (Exception ex) 69 | { 70 | if (throwException) 71 | { 72 | throw ex; 73 | } 74 | } 75 | return targetType.GetDefaultValueOfType(); 76 | } 77 | 78 | /// 79 | /// 任意类型的转化,如果 throwException=true 此方法会抛出异常,默认失败后不会抛出异常 80 | /// 81 | /// 82 | /// 83 | /// 84 | /// 是否抛出异常,默认否 85 | /// 86 | public static TReturnType To(this object value, TReturnType defaultValue = default(TReturnType), bool throwException = false) 87 | { 88 | if (value == null) 89 | { 90 | return defaultValue; 91 | } 92 | try 93 | { 94 | return (TReturnType)To(value, typeof(TReturnType), throwException); 95 | } 96 | catch (Exception ex) 97 | { 98 | if (throwException) 99 | { 100 | throw ex; 101 | } 102 | } 103 | return defaultValue; 104 | } 105 | /// 106 | /// 转化一个对象到 int 类型,此方法转化失败后不会抛异常 107 | /// 108 | /// 109 | /// 110 | public static int ToInt32(this object value) 111 | { 112 | return value.To(default(int), false); 113 | } 114 | 115 | /// 116 | /// 转化一个对象到 long 类型,此方法转化失败后不会抛异常 117 | /// 118 | /// 119 | /// 120 | public static long ToInt64(this object value) 121 | { 122 | return value.To(default(long), false); 123 | } 124 | 125 | /// 126 | /// 转化一个对象到 short 类型,此方法转化失败后不会抛异常 127 | /// 128 | /// 129 | /// 130 | public static short ToShort(this object value) 131 | { 132 | return value.To(default(short), false); 133 | } 134 | 135 | /// 136 | /// 转化一个对象到 DateTime 类型,此方法转化失败后不会抛异常 137 | /// 138 | /// 139 | /// 140 | public static DateTime ToDateTime(this object value) 141 | { 142 | return value.To(default(DateTime), false); 143 | } 144 | 145 | /// 146 | /// 转化一个对象到 Guid 类型,此方法转化失败后不会抛异常 147 | /// 148 | /// 149 | /// 150 | public static Guid ToGuid(this object value) 151 | { 152 | return value.To(default(Guid), false); 153 | } 154 | 155 | /// 156 | /// 转化一个对象到 bool 类型,此方法转化失败后不会抛异常 157 | /// 158 | /// 159 | /// 160 | public static bool ToBool(this object value) 161 | { 162 | return value.To(default(bool), false); 163 | } 164 | 165 | /// 166 | /// 转化一个对象到 float 类型,此方法转化失败后不会抛异常 167 | /// 168 | /// 169 | /// 170 | public static float ToFloat(this object value) 171 | { 172 | return value.To(default(float), false); 173 | } 174 | 175 | /// 176 | /// 转化一个对象到 double 类型,此方法转化失败后不会抛异常 177 | /// 178 | /// 179 | /// 180 | public static double ToDouble(this object value) 181 | { 182 | return value.To(default(double), false); 183 | } 184 | #endregion 185 | } -------------------------------------------------------------------------------- /MrHuo.Extensions.Test/StringExtensionsTest.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | 4 | namespace Tests 5 | { 6 | public class StringExtensionsTest 7 | { 8 | [Test] 9 | public void TestCount() 10 | { 11 | var str = "CABCDabcdecdCfcgdcd"; 12 | Assert.AreEqual(0, "".Count("a")); 13 | Assert.AreEqual(1, str.Count(str)); 14 | Assert.AreEqual(3, str.Count("cd")); 15 | Assert.AreEqual(4, str.Count("CD", true)); 16 | Assert.AreEqual(4, str.Count('c')); 17 | Assert.AreEqual(7, str.Count('C', true)); 18 | } 19 | 20 | [Test] 21 | public void TestRepeat() 22 | { 23 | var str = "hai"; 24 | Assert.AreEqual("haihaihai", str.Repeat(3)); 25 | Assert.AreEqual("hai", str.Repeat(0)); 26 | Assert.AreEqual(null, ((string)null)?.Repeat(0)); 27 | } 28 | 29 | [Test] 30 | public void TestCapitalize() 31 | { 32 | var str = "abcdefg"; 33 | Assert.AreEqual("Abcdefg", str.Capitalize()); 34 | Assert.AreEqual("ABCdefg", str.Capitalize(3)); 35 | Assert.AreEqual("abCDEfg", str.Capitalize(2, 3)); 36 | } 37 | 38 | [Test] 39 | public void TestIsUpper() 40 | { 41 | Assert.True("ABC".IsUpper()); 42 | Assert.False("ABc".IsUpper()); 43 | } 44 | 45 | [Test] 46 | public void TestIsLower() 47 | { 48 | Assert.False("ABC".IsLower()); 49 | Assert.True("abc".IsLower()); 50 | } 51 | 52 | [Test] 53 | public void TestIsNumeric() 54 | { 55 | Assert.True("+125.3554542".IsNumeric()); 56 | Assert.True("125".IsNumeric()); 57 | Assert.True("125.35".IsNumeric()); 58 | Assert.False("abc".IsNumeric()); 59 | } 60 | 61 | [Test] 62 | public void TestIsInt() 63 | { 64 | Assert.True("+125".IsInt()); 65 | Assert.False("+125.5".IsInt()); 66 | Assert.False("125.5".IsInt()); 67 | Assert.False("abc".IsInt()); 68 | } 69 | 70 | [Test] 71 | public void TestIsMobile() 72 | { 73 | Assert.True("13012341234".IsMobile()); 74 | Assert.True("14312341234".IsMobile()); 75 | Assert.False("1231341234".IsMobile()); 76 | Assert.False("123134123423".IsMobile()); 77 | Assert.False("abc".IsMobile()); 78 | Assert.False("+125".IsMobile()); 79 | } 80 | 81 | [Test] 82 | public void TestIsEmail() 83 | { 84 | Assert.True("13012341234@4234.com".IsEmail()); 85 | Assert.True("13012fwerewdf341234@4234.com".IsEmail()); 86 | Assert.False("13012341234".IsEmail()); 87 | Assert.False("13012341234@4234".IsEmail()); 88 | } 89 | 90 | [Test] 91 | public void TestIsUrl() 92 | { 93 | Assert.True("http://www.baidu.com/".IsUrl()); 94 | Assert.True("http://www.qq.com".IsUrl()); 95 | Assert.True("http://www.baidu.com/?kw=wrwer".IsUrl()); 96 | Assert.True("http://www.baidu.com?kw=wrwer&4fwer".IsUrl()); 97 | Assert.True("http://www.baidu.com?kw=wrwer&4fwer#wechat_redirect".IsUrl()); 98 | Assert.False("www.baidu.com".IsUrl()); 99 | Assert.True("www.baidu.com".IsUrl(includeProtocal: false)); 100 | } 101 | 102 | [Test] 103 | public void TestCenter() 104 | { 105 | var str = "hello"; 106 | Assert.AreEqual(" hello ", str.PadCenter(4 * 2 + str.Length)); 107 | Assert.AreEqual("====hello====", str.PadCenter('=', 4 * 2 + str.Length)); 108 | } 109 | 110 | [Test] 111 | public void TestBase64() 112 | { 113 | var str = "hello"; 114 | Assert.AreEqual("aGVsbG8=", str.ToBase64()); 115 | } 116 | 117 | [Test] 118 | public void TestReverse() 119 | { 120 | var str = "hello"; 121 | Assert.AreEqual("olleh", str.Reverse()); 122 | Assert.AreEqual("hello", str.Reverse().Reverse()); 123 | } 124 | 125 | [Test] 126 | public void TestLeft() 127 | { 128 | var str = "hello"; 129 | Assert.AreEqual(str, str.Left(-1)); 130 | Assert.AreEqual("he", str.Left(2)); 131 | Assert.AreEqual(str, str.Left(10)); 132 | } 133 | 134 | [Test] 135 | public void TestRight() 136 | { 137 | var str = "hello"; 138 | Assert.AreEqual(str, str.Right(-1)); 139 | Assert.AreEqual("lo", str.Right(2)); 140 | Assert.AreEqual(str, str.Right(10)); 141 | } 142 | 143 | [Test] 144 | public void TestSplitLines() 145 | { 146 | var str = "aa\nbb\r\ncc"; 147 | var expert = new string[] { "aa","bb","cc" }; 148 | Assert.AreEqual(expert, str.SplitLines()); 149 | } 150 | 151 | [Test] 152 | public void TestRemove() 153 | { 154 | var str = "aabbccdd"; 155 | Assert.AreEqual("aabbdd", str.Remove("cc")); 156 | Assert.AreEqual("aabbdd", str.Remove("c")); 157 | } 158 | 159 | [Test] 160 | public void TestTo() 161 | { 162 | var str = "123"; 163 | Assert.AreEqual(123, str.To()); 164 | Assert.AreEqual(123L, str.To()); 165 | Assert.AreEqual(123F, str.To()); 166 | Assert.AreEqual(123D, str.To()); 167 | Assert.AreEqual(true, "true".To()); 168 | Assert.AreEqual(false, "123".To()); 169 | Assert.AreEqual(false, "false".To()); 170 | } 171 | 172 | [Test] 173 | public void TestToHex() 174 | { 175 | var str = "123abc"; 176 | Assert.AreEqual("313233616263", str.ToHex()); 177 | } 178 | 179 | [Test] 180 | public void TestDESEncryptAndDESDecrypt() 181 | { 182 | var str = "abc"; 183 | Assert.AreEqual("qonwqDWxm9I=", str.DESEncrypt("123456")); 184 | Assert.AreEqual(str, "qonwqDWxm9I=".DESDecrypt("123456")); 185 | } 186 | 187 | [Test] 188 | public void TestToMd5() 189 | { 190 | Assert.AreEqual("E10ADC3949BA59ABBE56E057F20F883E", "123456".ToMd5()); 191 | Assert.AreEqual("900150983CD24FB0D6963F7D28E17F72", "abc".ToMd5()); 192 | } 193 | 194 | [Test] 195 | public void TestHtmlEncodeAndHtmlDecode() 196 | { 197 | var str = "

test

"; 198 | Assert.AreEqual("<h1>test</h1>", str.HtmlEncode()); 199 | Assert.AreEqual(str, "<h1>test</h1>".HtmlDecode()); 200 | } 201 | 202 | [Test] 203 | public void TestUrlEncodeAndUrlDecode() 204 | { 205 | var str = "?name=abc"; 206 | Assert.AreEqual("%3fname%3dabc", str.UrlEncode()); 207 | Assert.AreEqual(str, "%3fname%3dabc".UrlDecode()); 208 | } 209 | 210 | } 211 | } -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CommonTypeNameFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace MrHuo.Extensions 8 | { 9 | internal abstract class CommonTypeNameFormatter 10 | { 11 | protected abstract string GetPrimitiveTypeName(SpecialType type); 12 | 13 | protected abstract string GenericParameterOpening { get; } 14 | 15 | protected abstract string GenericParameterClosing { get; } 16 | 17 | protected abstract string ArrayOpening { get; } 18 | 19 | protected abstract string ArrayClosing { get; } 20 | 21 | protected abstract CommonPrimitiveFormatter PrimitiveFormatter { get; } 22 | 23 | public virtual string FormatTypeName(Type type) 24 | { 25 | if ((object)type == null) 26 | throw new ArgumentNullException(nameof(type)); 27 | string primitiveTypeName = this.GetPrimitiveTypeName(ObjectFormatterHelpers.GetPrimitiveSpecialType(type)); 28 | if (primitiveTypeName != null) 29 | return primitiveTypeName; 30 | if (type.IsGenericParameter) 31 | return type.Name; 32 | if (type.IsArray) 33 | return this.FormatArrayTypeName(type, null); 34 | System.Reflection.TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type); 35 | if (typeInfo.IsGenericType) 36 | return this.FormatGenericTypeName(typeInfo); 37 | return CommonTypeNameFormatter.FormatNonGenericTypeName(typeInfo); 38 | } 39 | 40 | private static string FormatNonGenericTypeName(System.Reflection.TypeInfo typeInfo) 41 | { 42 | if ((object)typeInfo.DeclaringType == null) 43 | return typeInfo.Name; 44 | List instance = new List(); 45 | do 46 | { 47 | instance.Add(typeInfo.Name); 48 | Type declaringType = typeInfo.DeclaringType; 49 | typeInfo = (object)declaringType != null ? IntrospectionExtensions.GetTypeInfo(declaringType) : null; 50 | } 51 | while (typeInfo != null); 52 | instance.Reverse(); 53 | return string.Join(".", instance); 54 | } 55 | 56 | public virtual string FormatTypeArguments(Type[] typeArguments) 57 | { 58 | if (typeArguments == null) 59 | throw new ArgumentNullException(nameof(typeArguments)); 60 | if (typeArguments.Length == 0) 61 | throw new ArgumentException(null, nameof(typeArguments)); 62 | StringBuilder builder = new StringBuilder(); 63 | builder.Append(this.GenericParameterOpening); 64 | bool flag = true; 65 | foreach (Type typeArgument in typeArguments) 66 | { 67 | if (flag) 68 | flag = false; 69 | else 70 | builder.Append(", "); 71 | builder.Append(this.FormatTypeName(typeArgument)); 72 | } 73 | builder.Append(this.GenericParameterClosing); 74 | return builder.ToString(); 75 | } 76 | 77 | public virtual string FormatArrayTypeName( 78 | Type arrayType, 79 | Array arrayOpt) 80 | { 81 | if ((object)arrayType == null) 82 | throw new ArgumentNullException(nameof(arrayType)); 83 | StringBuilder sb = new StringBuilder(); 84 | Type elementType = arrayType.GetElementType(); 85 | while (elementType.IsArray) 86 | elementType = elementType.GetElementType(); 87 | sb.Append(this.FormatTypeName(elementType)); 88 | Type arrayType1 = arrayType; 89 | do 90 | { 91 | if (arrayOpt != null) 92 | { 93 | sb.Append(this.ArrayOpening); 94 | int arrayRank = arrayType1.GetArrayRank(); 95 | bool flag = false; 96 | for (int dimension = 0; dimension < arrayRank; ++dimension) 97 | { 98 | if (arrayOpt.GetLowerBound(dimension) > 0) 99 | { 100 | flag = true; 101 | break; 102 | } 103 | } 104 | for (int dimension = 0; dimension < arrayRank; ++dimension) 105 | { 106 | int lowerBound = arrayOpt.GetLowerBound(dimension); 107 | int length = arrayOpt.GetLength(dimension); 108 | if (dimension > 0) 109 | sb.Append(", "); 110 | if (flag) 111 | { 112 | this.AppendArrayBound(sb, lowerBound); 113 | sb.Append(".."); 114 | this.AppendArrayBound(sb, length + lowerBound); 115 | } 116 | else 117 | this.AppendArrayBound(sb, length); 118 | } 119 | sb.Append(this.ArrayClosing); 120 | arrayOpt = null; 121 | } 122 | else 123 | this.AppendArrayRank(sb, arrayType1); 124 | arrayType1 = arrayType1.GetElementType(); 125 | } 126 | while (arrayType1.IsArray); 127 | return sb.ToString(); 128 | } 129 | 130 | private void AppendArrayBound(StringBuilder sb, long bound) 131 | { 132 | CommonPrimitiveFormatterOptions options = new CommonPrimitiveFormatterOptions(); 133 | string str = int.MinValue > bound || bound > int.MaxValue ? this.PrimitiveFormatter.FormatPrimitive(bound, options) : this.PrimitiveFormatter.FormatPrimitive((int)bound, options); 134 | sb.Append(str); 135 | } 136 | 137 | private void AppendArrayRank(StringBuilder sb, Type arrayType) 138 | { 139 | sb.Append('['); 140 | int arrayRank = arrayType.GetArrayRank(); 141 | if (arrayRank > 1) 142 | sb.Append(',', arrayRank - 1); 143 | sb.Append(']'); 144 | } 145 | 146 | private string FormatGenericTypeName(System.Reflection.TypeInfo typeInfo) 147 | { 148 | StringBuilder builder = new StringBuilder(); 149 | Type[] genericArguments = typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters : typeInfo.GenericTypeArguments; 150 | if ((object)typeInfo.DeclaringType != null) 151 | { 152 | List instance2 = new List(); 153 | do 154 | { 155 | instance2.Add(typeInfo); 156 | Type declaringType = typeInfo.DeclaringType; 157 | typeInfo = (object)declaringType != null ? IntrospectionExtensions.GetTypeInfo(declaringType) : null; 158 | } 159 | while (typeInfo != null); 160 | int genericArgIndex = 0; 161 | for (int index = instance2.Count - 1; index >= 0; --index) 162 | { 163 | this.AppendTypeInstantiation(builder, instance2[index], genericArguments, ref genericArgIndex); 164 | if (index > 0) 165 | builder.Append('.'); 166 | } 167 | } 168 | else 169 | { 170 | int genericArgIndex = 0; 171 | this.AppendTypeInstantiation(builder, typeInfo, genericArguments, ref genericArgIndex); 172 | } 173 | return builder.ToString(); 174 | } 175 | 176 | private void AppendTypeInstantiation( 177 | StringBuilder builder, 178 | System.Reflection.TypeInfo typeInfo, 179 | Type[] genericArguments, 180 | ref int genericArgIndex) 181 | { 182 | int num = (typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters.Length : typeInfo.GenericTypeArguments.Length) - genericArgIndex; 183 | if (num > 0) 184 | { 185 | string name = typeInfo.Name; 186 | int length = name.IndexOf('`'); 187 | if (length > 0) 188 | builder.Append(name.Substring(0, length)); 189 | else 190 | builder.Append(name); 191 | builder.Append(this.GenericParameterOpening); 192 | for (int index = 0; index < num; ++index) 193 | { 194 | if (index > 0) 195 | builder.Append(", "); 196 | builder.Append(this.FormatTypeName(genericArguments[genericArgIndex++])); 197 | } 198 | builder.Append(this.GenericParameterClosing); 199 | } 200 | else 201 | builder.Append(typeInfo.Name); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/ObjectDisplay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Text; 4 | 5 | namespace MrHuo.Extensions 6 | { 7 | internal static class ObjectDisplay 8 | { 9 | internal static string NullLiteral 10 | { 11 | get 12 | { 13 | return "null"; 14 | } 15 | } 16 | 17 | internal static string FormatLiteral(bool value) 18 | { 19 | return !value ? "false" : "true"; 20 | } 21 | 22 | private static bool TryReplaceChar(char c, out string replaceWith) 23 | { 24 | replaceWith = null; 25 | switch (c) 26 | { 27 | case char.MinValue: 28 | replaceWith = "\\0"; 29 | break; 30 | case '\a': 31 | replaceWith = "\\a"; 32 | break; 33 | case '\b': 34 | replaceWith = "\\b"; 35 | break; 36 | case '\t': 37 | replaceWith = "\\t"; 38 | break; 39 | case '\n': 40 | replaceWith = "\\n"; 41 | break; 42 | case '\v': 43 | replaceWith = "\\v"; 44 | break; 45 | case '\f': 46 | replaceWith = "\\f"; 47 | break; 48 | case '\r': 49 | replaceWith = "\\r"; 50 | break; 51 | case '\\': 52 | replaceWith = "\\\\"; 53 | break; 54 | } 55 | if (replaceWith != null) 56 | return true; 57 | if (!ObjectDisplay.NeedsEscaping(CharUnicodeInfo.GetUnicodeCategory(c))) 58 | return false; 59 | replaceWith = "\\u" + ((int)c).ToString("x4"); 60 | return true; 61 | } 62 | 63 | private static bool NeedsEscaping(UnicodeCategory category) 64 | { 65 | switch (category) 66 | { 67 | case UnicodeCategory.LineSeparator: 68 | case UnicodeCategory.ParagraphSeparator: 69 | case UnicodeCategory.Control: 70 | case UnicodeCategory.Surrogate: 71 | case UnicodeCategory.OtherNotAssigned: 72 | return true; 73 | default: 74 | return false; 75 | } 76 | } 77 | 78 | public static string FormatLiteral(string value, ObjectDisplayOptions options) 79 | { 80 | if (value == null) 81 | throw new ArgumentNullException(nameof(value)); 82 | StringBuilder builder = new StringBuilder(); 83 | bool flag1 = options.IncludesOption(ObjectDisplayOptions.UseQuotes); 84 | bool flag2 = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableCharacters); 85 | bool flag3 = flag1 && !flag2 && ObjectDisplay.ContainsNewLine(value); 86 | if (flag1) 87 | { 88 | if (flag3) 89 | builder.Append('@'); 90 | builder.Append('"'); 91 | } 92 | for (int index = 0; index < value.Length; ++index) 93 | { 94 | char ch = value[index]; 95 | if (flag2 && CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.Surrogate) 96 | { 97 | UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(value, index); 98 | if (unicodeCategory == UnicodeCategory.Surrogate) 99 | builder.Append("\\u" + ((int)ch).ToString("x4")); 100 | else if (ObjectDisplay.NeedsEscaping(unicodeCategory)) 101 | { 102 | int utf32 = char.ConvertToUtf32(value, index); 103 | builder.Append("\\U" + utf32.ToString("x8")); 104 | ++index; 105 | } 106 | else 107 | { 108 | builder.Append(ch); 109 | builder.Append(value[++index]); 110 | } 111 | } 112 | else 113 | { 114 | string replaceWith; 115 | if (flag2 && ObjectDisplay.TryReplaceChar(ch, out replaceWith)) 116 | builder.Append(replaceWith); 117 | else if (flag1 && ch == '"') 118 | { 119 | if (flag3) 120 | { 121 | builder.Append('"'); 122 | builder.Append('"'); 123 | } 124 | else 125 | { 126 | builder.Append('\\'); 127 | builder.Append('"'); 128 | } 129 | } 130 | else 131 | builder.Append(ch); 132 | } 133 | } 134 | if (flag1) 135 | builder.Append('"'); 136 | return builder.ToString(); 137 | } 138 | 139 | private static bool IsNewLine(char ch) 140 | { 141 | if (ch != '\r' && ch != '\n' && (ch != '\x0085' && ch != '\x2028')) 142 | return ch == '\x2029'; 143 | return true; 144 | } 145 | 146 | private static bool ContainsNewLine(string s) 147 | { 148 | foreach (char ch in s) 149 | { 150 | if (IsNewLine(ch)) 151 | return true; 152 | } 153 | return false; 154 | } 155 | 156 | internal static string FormatLiteral(char c, ObjectDisplayOptions options) 157 | { 158 | StringBuilder builder = new StringBuilder(); 159 | if (options.IncludesOption(ObjectDisplayOptions.IncludeCodePoints)) 160 | { 161 | builder.Append(options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers) ? "0x" + ((int)c).ToString("x4") : ((int)c).ToString()); 162 | builder.Append(" "); 163 | } 164 | bool flag1 = options.IncludesOption(ObjectDisplayOptions.UseQuotes); 165 | bool flag2 = options.IncludesOption(ObjectDisplayOptions.EscapeNonPrintableCharacters); 166 | if (flag1) 167 | builder.Append('\''); 168 | string replaceWith; 169 | if (flag2 && ObjectDisplay.TryReplaceChar(c, out replaceWith)) 170 | builder.Append(replaceWith); 171 | else if (flag1 && c == '\'') 172 | { 173 | builder.Append('\\'); 174 | builder.Append('\''); 175 | } 176 | else 177 | builder.Append(c); 178 | if (flag1) 179 | builder.Append('\''); 180 | return builder.ToString(); 181 | } 182 | 183 | internal static string FormatLiteral( 184 | sbyte value, 185 | ObjectDisplayOptions options, 186 | CultureInfo cultureInfo = null) 187 | { 188 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 189 | return "0x" + (value >= 0 ? value.ToString("x2") : ((int)value).ToString("x8")); 190 | return value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 191 | } 192 | 193 | internal static string FormatLiteral( 194 | byte value, 195 | ObjectDisplayOptions options, 196 | CultureInfo cultureInfo = null) 197 | { 198 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 199 | return "0x" + value.ToString("x2"); 200 | return value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 201 | } 202 | 203 | internal static string FormatLiteral( 204 | short value, 205 | ObjectDisplayOptions options, 206 | CultureInfo cultureInfo = null) 207 | { 208 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 209 | return "0x" + (value >= 0 ? value.ToString("x4") : ((int)value).ToString("x8")); 210 | return value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 211 | } 212 | 213 | internal static string FormatLiteral( 214 | ushort value, 215 | ObjectDisplayOptions options, 216 | CultureInfo cultureInfo = null) 217 | { 218 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 219 | return "0x" + value.ToString("x4"); 220 | return value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 221 | } 222 | 223 | internal static string FormatLiteral( 224 | int value, 225 | ObjectDisplayOptions options, 226 | CultureInfo cultureInfo = null) 227 | { 228 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 229 | return "0x" + value.ToString("x8"); 230 | return value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 231 | } 232 | 233 | internal static string FormatLiteral( 234 | uint value, 235 | ObjectDisplayOptions options, 236 | CultureInfo cultureInfo = null) 237 | { 238 | StringBuilder builder = new StringBuilder(); 239 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 240 | { 241 | builder.Append("0x"); 242 | builder.Append(value.ToString("x8")); 243 | } 244 | else 245 | builder.Append(value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo))); 246 | if (options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 247 | builder.Append('U'); 248 | return builder.ToString(); 249 | } 250 | 251 | internal static string FormatLiteral( 252 | long value, 253 | ObjectDisplayOptions options, 254 | CultureInfo cultureInfo = null) 255 | { 256 | StringBuilder builder = new StringBuilder(); 257 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 258 | { 259 | builder.Append("0x"); 260 | builder.Append(value.ToString("x16")); 261 | } 262 | else 263 | builder.Append(value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo))); 264 | if (options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 265 | builder.Append('L'); 266 | return builder.ToString(); 267 | } 268 | 269 | internal static string FormatLiteral( 270 | ulong value, 271 | ObjectDisplayOptions options, 272 | CultureInfo cultureInfo = null) 273 | { 274 | StringBuilder builder = new StringBuilder(); 275 | if (options.IncludesOption(ObjectDisplayOptions.UseHexadecimalNumbers)) 276 | { 277 | builder.Append("0x"); 278 | builder.Append(value.ToString("x16")); 279 | } 280 | else 281 | builder.Append(value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo))); 282 | if (options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 283 | builder.Append("UL"); 284 | return builder.ToString(); 285 | } 286 | 287 | internal static string FormatLiteral( 288 | double value, 289 | ObjectDisplayOptions options, 290 | CultureInfo cultureInfo = null) 291 | { 292 | string str = value.ToString("R", ObjectDisplay.GetFormatCulture(cultureInfo)); 293 | if (!options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 294 | return str; 295 | return str + "D"; 296 | } 297 | 298 | internal static string FormatLiteral( 299 | float value, 300 | ObjectDisplayOptions options, 301 | CultureInfo cultureInfo = null) 302 | { 303 | string str = value.ToString("R", ObjectDisplay.GetFormatCulture(cultureInfo)); 304 | if (!options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 305 | return str; 306 | return str + "F"; 307 | } 308 | 309 | internal static string FormatLiteral( 310 | Decimal value, 311 | ObjectDisplayOptions options, 312 | CultureInfo cultureInfo = null) 313 | { 314 | string str = value.ToString(ObjectDisplay.GetFormatCulture(cultureInfo)); 315 | if (!options.IncludesOption(ObjectDisplayOptions.IncludeTypeSuffix)) 316 | return str; 317 | return str + "M"; 318 | } 319 | 320 | private static CultureInfo GetFormatCulture(CultureInfo cultureInfo) 321 | { 322 | return cultureInfo ?? CultureInfo.InvariantCulture; 323 | } 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/GeneratedNames.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Text; 4 | 5 | namespace MrHuo.Extensions 6 | { 7 | internal static class GeneratedNames 8 | { 9 | internal const string SynthesizedLocalNamePrefix = "CS$"; 10 | internal const char DotReplacementInTypeNames = '-'; 11 | private const string SuffixSeparator = "__"; 12 | private const char IdSeparator = '_'; 13 | private const char GenerationSeparator = '#'; 14 | private const char LocalFunctionNameTerminator = '|'; 15 | internal const string AnonymousNamePrefix = "<>f__AnonymousType"; 16 | 17 | internal static bool IsGeneratedMemberName(string memberName) 18 | { 19 | if (memberName.Length > 0) 20 | return memberName[0] == '<'; 21 | return false; 22 | } 23 | 24 | internal static string MakeBackingFieldName(string propertyName) 25 | { 26 | return "<" + propertyName + ">k__BackingField"; 27 | } 28 | 29 | internal static string MakeIteratorFinallyMethodName(int iteratorState) 30 | { 31 | return "<>m__Finally" + StringExtensions.GetNumeral(Math.Abs(iteratorState + 2)); 32 | } 33 | 34 | internal static string MakeStaticLambdaDisplayClassName(int methodOrdinal, int generation) 35 | { 36 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.LambdaDisplayClass, methodOrdinal, generation, null, null, char.MinValue, -1, -1); 37 | } 38 | 39 | internal static string MakeLambdaDisplayClassName( 40 | int methodOrdinal, 41 | int generation, 42 | int closureOrdinal, 43 | int closureGeneration) 44 | { 45 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.LambdaDisplayClass, methodOrdinal, generation, null, "DisplayClass", char.MinValue, closureOrdinal, closureGeneration); 46 | } 47 | 48 | internal static string MakeAnonymousTypeTemplateName( 49 | int index, 50 | int submissionSlotIndex, 51 | string moduleId) 52 | { 53 | string str = "<" + moduleId + ">f__AnonymousType" + StringExtensions.GetNumeral(index); 54 | if (submissionSlotIndex >= 0) 55 | str = str + "#" + StringExtensions.GetNumeral(submissionSlotIndex); 56 | return str; 57 | } 58 | 59 | internal static bool TryParseAnonymousTypeTemplateName(string name, out int index) 60 | { 61 | if (name.StartsWith("<>f__AnonymousType", StringComparison.Ordinal) && int.TryParse(name.Substring("<>f__AnonymousType".Length), NumberStyles.None, CultureInfo.InvariantCulture, out index)) 62 | return true; 63 | index = -1; 64 | return false; 65 | } 66 | 67 | internal static string MakeAnonymousTypeBackingFieldName(string propertyName) 68 | { 69 | return "<" + propertyName + ">i__Field"; 70 | } 71 | 72 | internal static string MakeAnonymousTypeParameterName(string propertyName) 73 | { 74 | return "<" + propertyName + ">j__TPar"; 75 | } 76 | 77 | internal static bool TryParseAnonymousTypeParameterName( 78 | string typeParameterName, 79 | out string propertyName) 80 | { 81 | if (typeParameterName.StartsWith("<", StringComparison.Ordinal) && typeParameterName.EndsWith(">j__TPar", StringComparison.Ordinal)) 82 | { 83 | propertyName = typeParameterName.Substring(1, typeParameterName.Length - 9); 84 | return true; 85 | } 86 | propertyName = null; 87 | return false; 88 | } 89 | 90 | internal static string MakeStateMachineTypeName( 91 | string methodName, 92 | int methodOrdinal, 93 | int generation) 94 | { 95 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.StateMachineType, methodOrdinal, generation, methodName, null, char.MinValue, -1, -1); 96 | } 97 | 98 | internal static string MakeBaseMethodWrapperName(int uniqueId) 99 | { 100 | return "<>n__" + StringExtensions.GetNumeral(uniqueId); 101 | } 102 | 103 | internal static string MakeLambdaMethodName( 104 | string methodName, 105 | int methodOrdinal, 106 | int methodGeneration, 107 | int lambdaOrdinal, 108 | int lambdaGeneration) 109 | { 110 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.LambdaMethod, methodOrdinal, methodGeneration, methodName, null, char.MinValue, lambdaOrdinal, lambdaGeneration); 111 | } 112 | 113 | internal static string MakeLambdaCacheFieldName( 114 | int methodOrdinal, 115 | int generation, 116 | int lambdaOrdinal, 117 | int lambdaGeneration) 118 | { 119 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.LambdaCacheField, methodOrdinal, generation, null, null, char.MinValue, lambdaOrdinal, lambdaGeneration); 120 | } 121 | 122 | internal static string MakeLocalFunctionName( 123 | string methodName, 124 | string localFunctionName, 125 | int methodOrdinal, 126 | int methodGeneration, 127 | int lambdaOrdinal, 128 | int lambdaGeneration) 129 | { 130 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.LocalFunction, methodOrdinal, methodGeneration, methodName, localFunctionName, '|', lambdaOrdinal, lambdaGeneration); 131 | } 132 | 133 | private static string MakeMethodScopedSynthesizedName( 134 | GeneratedNameKind kind, 135 | int methodOrdinal, 136 | int methodGeneration, 137 | string methodNameOpt = null, 138 | string suffix = null, 139 | char suffixTerminator = '\0', 140 | int entityOrdinal = -1, 141 | int entityGeneration = -1) 142 | { 143 | StringBuilder builder = new StringBuilder(); 144 | builder.Append('<'); 145 | if (methodNameOpt != null) 146 | { 147 | builder.Append(methodNameOpt); 148 | if (kind.IsTypeName()) 149 | builder.Replace('.', '-'); 150 | } 151 | builder.Append('>'); 152 | builder.Append((char)kind); 153 | if (suffix != null || methodOrdinal >= 0 || entityOrdinal >= 0) 154 | { 155 | builder.Append("__"); 156 | builder.Append(suffix); 157 | if (suffixTerminator != char.MinValue) 158 | builder.Append(suffixTerminator); 159 | if (methodOrdinal >= 0) 160 | { 161 | builder.Append(methodOrdinal); 162 | GeneratedNames.AppendOptionalGeneration(builder, methodGeneration); 163 | } 164 | if (entityOrdinal >= 0) 165 | { 166 | if (methodOrdinal >= 0) 167 | builder.Append('_'); 168 | builder.Append(entityOrdinal); 169 | GeneratedNames.AppendOptionalGeneration(builder, entityGeneration); 170 | } 171 | } 172 | return builder.ToString(); 173 | } 174 | 175 | private static void AppendOptionalGeneration(StringBuilder builder, int generation) 176 | { 177 | if (generation <= 0) 178 | return; 179 | builder.Append('#'); 180 | builder.Append(generation); 181 | } 182 | 183 | internal static GeneratedNameKind GetKind(string name) 184 | { 185 | GeneratedNameKind kind; 186 | int openBracketOffset; 187 | int closeBracketOffset; 188 | if (!GeneratedNames.TryParseGeneratedName(name, out kind, out openBracketOffset, out closeBracketOffset)) 189 | return GeneratedNameKind.None; 190 | return kind; 191 | } 192 | 193 | internal static bool TryParseGeneratedName( 194 | string name, 195 | out GeneratedNameKind kind, 196 | out int openBracketOffset, 197 | out int closeBracketOffset) 198 | { 199 | openBracketOffset = -1; 200 | if (name.StartsWith("CS$<", StringComparison.Ordinal)) 201 | openBracketOffset = 3; 202 | else if (name.StartsWith("<", StringComparison.Ordinal)) 203 | openBracketOffset = 0; 204 | if (openBracketOffset >= 0) 205 | { 206 | closeBracketOffset = name.IndexOfBalancedParenthesis(openBracketOffset, '>'); 207 | if (closeBracketOffset >= 0 && closeBracketOffset + 1 < name.Length) 208 | { 209 | int num = name[closeBracketOffset + 1]; 210 | if (num >= 49 && num <= 57 || num >= 97 && num <= 122) 211 | { 212 | kind = (GeneratedNameKind)num; 213 | return true; 214 | } 215 | } 216 | } 217 | kind = GeneratedNameKind.None; 218 | openBracketOffset = -1; 219 | closeBracketOffset = -1; 220 | return false; 221 | } 222 | 223 | internal static bool TryParseSourceMethodNameFromGeneratedName( 224 | string generatedName, 225 | GeneratedNameKind requiredKind, 226 | out string methodName) 227 | { 228 | GeneratedNameKind kind; 229 | int openBracketOffset; 230 | int closeBracketOffset; 231 | if (!GeneratedNames.TryParseGeneratedName(generatedName, out kind, out openBracketOffset, out closeBracketOffset)) 232 | { 233 | methodName = null; 234 | return false; 235 | } 236 | if (requiredKind != GeneratedNameKind.None && kind != requiredKind) 237 | { 238 | methodName = null; 239 | return false; 240 | } 241 | methodName = generatedName.Substring(openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); 242 | if (kind.IsTypeName()) 243 | methodName = methodName.Replace('-', '.'); 244 | return true; 245 | } 246 | 247 | internal static string AsyncAwaiterFieldName(int slotIndex) 248 | { 249 | return "<>u__" + StringExtensions.GetNumeral(slotIndex + 1); 250 | } 251 | 252 | internal static bool TryParseSlotIndex(string fieldName, out int slotIndex) 253 | { 254 | int num = fieldName.LastIndexOf('_'); 255 | if (num - 1 < 0 || num == fieldName.Length || fieldName[num - 1] != '_') 256 | { 257 | slotIndex = -1; 258 | return false; 259 | } 260 | if (int.TryParse(fieldName.Substring(num + 1), NumberStyles.None, CultureInfo.InvariantCulture, out slotIndex) && slotIndex >= 1) 261 | { 262 | --slotIndex; 263 | return true; 264 | } 265 | slotIndex = -1; 266 | return false; 267 | } 268 | 269 | internal static string MakeCachedFrameInstanceFieldName() 270 | { 271 | return "<>9"; 272 | } 273 | 274 | internal static string MakeLambdaDisplayLocalName(int uniqueId) 275 | { 276 | return "CS$<>8__locals" + StringExtensions.GetNumeral(uniqueId); 277 | } 278 | 279 | internal static bool IsSynthesizedLocalName(string name) 280 | { 281 | return name.StartsWith("CS$", StringComparison.Ordinal); 282 | } 283 | 284 | internal static string MakeFixedFieldImplementationName(string fieldName) 285 | { 286 | return "<" + fieldName + ">e__FixedBuffer"; 287 | } 288 | 289 | internal static string MakeStateMachineStateFieldName() 290 | { 291 | return "<>1__state"; 292 | } 293 | 294 | internal static string MakeIteratorCurrentFieldName() 295 | { 296 | return "<>2__current"; 297 | } 298 | 299 | internal static string MakeIteratorCurrentThreadIdFieldName() 300 | { 301 | return "<>l__initialThreadId"; 302 | } 303 | 304 | internal static string ThisProxyFieldName() 305 | { 306 | return "<>4__this"; 307 | } 308 | 309 | internal static string StateMachineThisParameterProxyName() 310 | { 311 | return GeneratedNames.StateMachineParameterProxyFieldName(GeneratedNames.ThisProxyFieldName()); 312 | } 313 | 314 | internal static string StateMachineParameterProxyFieldName(string parameterName) 315 | { 316 | return "<>3__" + parameterName; 317 | } 318 | 319 | internal static string MakeDynamicCallSiteContainerName(int methodOrdinal, int generation) 320 | { 321 | return GeneratedNames.MakeMethodScopedSynthesizedName(GeneratedNameKind.DynamicCallSiteContainerType, methodOrdinal, generation, null, null, char.MinValue, -1, -1); 322 | } 323 | 324 | internal static string MakeDynamicCallSiteFieldName(int uniqueId) 325 | { 326 | return "<>p__" + StringExtensions.GetNumeral(uniqueId); 327 | } 328 | 329 | internal static string AsyncBuilderFieldName() 330 | { 331 | return "<>t__builder"; 332 | } 333 | 334 | internal static string ReusableHoistedLocalFieldName(int number) 335 | { 336 | return "<>7__wrap" + StringExtensions.GetNumeral(number); 337 | } 338 | 339 | internal static string LambdaCopyParameterName(int ordinal) 340 | { 341 | return ""; 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ExcelHelper.cs: -------------------------------------------------------------------------------- 1 | using NPOI.HSSF.UserModel; 2 | using NPOI.SS.UserModel; 3 | using NPOI.XSSF.UserModel; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Data; 7 | using System.IO; 8 | 9 | namespace MrHuo.Extensions 10 | { 11 | /// 12 | /// Excel 帮助类 13 | /// 包含功能:Excel 导入,Excel 导出 14 | /// 15 | public static class ExcelHelper 16 | { 17 | #region [ICellExtensions] 18 | /// 19 | /// 获取单元格的数据 20 | /// 21 | /// 22 | /// 23 | public static object GetCellValue(this ICell cell) 24 | { 25 | switch (cell.CellType) 26 | { 27 | case CellType.Numeric: 28 | return cell.NumericCellValue; 29 | case CellType.Formula: 30 | return cell.CellFormula; 31 | case CellType.Boolean: 32 | return cell.BooleanCellValue; 33 | case CellType.Blank: 34 | case CellType.String: 35 | case CellType.Unknown: 36 | default: 37 | try 38 | { 39 | return cell.StringCellValue; 40 | } 41 | catch (Exception ex) 42 | { 43 | return null; 44 | } 45 | } 46 | } 47 | #endregion 48 | 49 | #region [Import] 50 | /// 51 | /// 从 Excel 导入数据 52 | /// 53 | /// 54 | /// Excel 文件 55 | /// 列定义 56 | /// 是否包含标题行,默认包含 57 | /// 标题行数,默认1行 58 | /// Sheet 索引 59 | /// 60 | public static List Import( 61 | string excelFile, 62 | List<(string PropertyName, int? ColumnIndex, Func ValueProceed)> columnsDef, 63 | bool includeTitleRow = true, 64 | int titleRowNum = 1, 65 | int sheetIndex = 0) 66 | where T : new() 67 | { 68 | Ensure.FileExists(excelFile); 69 | Ensure.NotNull(columnsDef, nameof(columnsDef)); 70 | Ensure.HasValue(columnsDef); 71 | 72 | IWorkbook workbook = null; 73 | FileStream hssfWorkbookFileStream = null; 74 | var fileExt = excelFile.GetFileExtensions(); 75 | if (fileExt == ".xls") 76 | { 77 | hssfWorkbookFileStream = excelFile.GetReadStream(); 78 | workbook = new HSSFWorkbook(hssfWorkbookFileStream); 79 | } 80 | else 81 | { 82 | workbook = new XSSFWorkbook(excelFile); 83 | } 84 | var sheetNums = workbook.NumberOfSheets; 85 | if (sheetNums == 0) 86 | { 87 | throw new Exception($"该 Excel 文件[{excelFile}]不存在任何 Sheet"); 88 | } 89 | if (sheetIndex > sheetNums - 1) 90 | { 91 | throw new Exception($"该 Excel 文件共有 {sheetNums} 个 Sheet,不存在索引为 {sheetIndex} 的 Sheet"); 92 | } 93 | var sheet = workbook.GetSheetAt(sheetIndex); 94 | var rowNums = sheet.PhysicalNumberOfRows - (includeTitleRow ? titleRowNum : 0); 95 | var startRowIndex = sheet.FirstRowNum + (includeTitleRow ? titleRowNum : 0); 96 | 97 | var ret = new List(); 98 | var properties = typeof(T).GetProperties(); 99 | for (int rowNo = 0; rowNo < rowNums; rowNo++) 100 | { 101 | var row = sheet.GetRow(startRowIndex + rowNo); 102 | if (row == null) 103 | { 104 | continue; 105 | } 106 | var cols = row.Cells; 107 | if (cols == null || cols.Count == 0) 108 | { 109 | continue; 110 | } 111 | var dataItem = new T(); 112 | var hasError = false; 113 | foreach (var def in columnsDef) 114 | { 115 | var property = dataItem.GetProperty(def.PropertyName); 116 | if (property == null) 117 | { 118 | continue; 119 | } 120 | try 121 | { 122 | object data = null; 123 | if (def.ColumnIndex == null) 124 | { 125 | if (def.ValueProceed != null) 126 | { 127 | data = def.ValueProceed(data); 128 | } 129 | } 130 | else 131 | { 132 | if (def.ColumnIndex.Value <= cols.Count - 1) 133 | { 134 | var col = cols[def.ColumnIndex.Value]; 135 | if (col != null) 136 | { 137 | object value = col.GetCellValue(); 138 | data = value.To(property.PropertyType); 139 | if (def.ValueProceed != null) 140 | { 141 | data = def.ValueProceed(data); 142 | } 143 | } 144 | } 145 | } 146 | dataItem.SetValue(def.PropertyName, data); 147 | } 148 | catch (Exception ex) 149 | { 150 | Console.WriteLine("EXCEPTION: " + ex.ToString()); 151 | hasError = true; 152 | } 153 | } 154 | if (!hasError) 155 | { 156 | ret.Add(dataItem); 157 | } 158 | } 159 | workbook.Close(); 160 | if (hssfWorkbookFileStream != null) 161 | { 162 | hssfWorkbookFileStream.Close(); 163 | } 164 | return ret; 165 | } 166 | #endregion 167 | 168 | #region [ExportDataTable] 169 | /// 170 | /// 导出 DataTable 到 Excel 文件 171 | /// 172 | /// 需要导出的 DataTable 173 | /// Sheet名称,默认 Sheet1 174 | /// Excel 文件路径,默认为空,创建一个临时文件 175 | /// 是否包含标题行,默认为true(包含) 176 | /// 导出的Excel文件绝对地址 177 | public static string ExportToFile( 178 | DataTable dataTable, 179 | string sheetName = null, 180 | string saveFile = null, 181 | bool includeTitleRow = true 182 | ) 183 | { 184 | Ensure.NotNull(dataTable, nameof(dataTable)); 185 | if (string.IsNullOrEmpty(saveFile)) 186 | { 187 | saveFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("n") + ".xls"); 188 | } 189 | if (File.Exists(saveFile)) 190 | { 191 | File.Delete(saveFile); 192 | } 193 | using (var stream = ExportToMemoryStream(dataTable, sheetName ?? "Sheet1", includeTitleRow)) 194 | { 195 | using (FileStream fs = new FileStream(saveFile, FileMode.Create, FileAccess.Write)) 196 | { 197 | byte[] data = stream.ToArray(); 198 | fs.Write(data, 0, data.Length); 199 | fs.Flush(); 200 | } 201 | } 202 | return saveFile; 203 | } 204 | 205 | /// 206 | /// 导出 DataTable 到 MemoryStream 207 | /// 208 | /// 需要导出的 DataTable 209 | /// Sheet名称,默认 Sheet1 210 | /// 是否包含标题行,默认为true(包含) 211 | /// MemoryStream 212 | public static MemoryStream ExportToMemoryStream( 213 | DataTable dataTable, 214 | string sheetName = null, 215 | bool includeTitleRow = true 216 | ) 217 | { 218 | Ensure.NotNull(dataTable, nameof(dataTable)); 219 | var workbook = new XSSFWorkbook(); 220 | var sheet1 = workbook.CreateSheet(sheetName ?? "Sheet1"); 221 | if (includeTitleRow) 222 | { 223 | //输出标题 224 | var titleRow = sheet1.CreateRow(0); 225 | var colIndex = 0; 226 | foreach (DataColumn item in dataTable.Columns) 227 | { 228 | titleRow.CreateCell(colIndex++).SetCellValue(item.ColumnName); 229 | } 230 | } 231 | //输出内容 232 | var rowIndex = includeTitleRow ? 1 : 0; 233 | foreach (DataRow tableRow in dataTable.Rows) 234 | { 235 | var row = sheet1.CreateRow(rowIndex++); 236 | var colIndex = 0; 237 | foreach (DataColumn col in dataTable.Columns) 238 | { 239 | row.CreateCell(colIndex++).SetCellValue($"{tableRow[col]}"); 240 | } 241 | } 242 | var ms = new MemoryStream(); 243 | workbook.Write(ms); 244 | ms.Flush(); 245 | return ms; 246 | } 247 | #endregion 248 | 249 | #region [ExportIEnumerable] 250 | /// 251 | /// 导出 IEnumerable 到 Excel 文件 252 | /// 253 | /// 任意类型 254 | /// IEnumerable 255 | /// 列定义,默认为 null,通过反射的方式确定列名 256 | /// Sheet名称,默认 Sheet1 257 | /// Excel 文件路径,默认为空,创建一个临时文件 258 | /// 是否包含标题行,默认为true(包含) 259 | /// 导出的Excel文件绝对地址 260 | public static string ExportToFile( 261 | IEnumerable data, 262 | Dictionary> columnDef = null, 263 | string sheetName = null, 264 | string saveFile = null, 265 | bool includeTitleRow = true 266 | ) 267 | { 268 | Ensure.NotNull(data, nameof(data)); 269 | if (string.IsNullOrEmpty(saveFile)) 270 | { 271 | saveFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("n") + ".xls"); 272 | } 273 | if (File.Exists(saveFile)) 274 | { 275 | File.Delete(saveFile); 276 | } 277 | var dir = Path.GetDirectoryName(saveFile); 278 | if (!Directory.Exists(dir)) 279 | { 280 | Directory.CreateDirectory(dir); 281 | } 282 | sheetName = sheetName ?? "Sheet1"; 283 | using (var stream = ExportToMemoryStream(data, columnDef, sheetName, includeTitleRow)) 284 | { 285 | using (FileStream fs = new FileStream(saveFile, FileMode.Create, FileAccess.Write)) 286 | { 287 | byte[] dataArray = stream.ToArray(); 288 | fs.Write(dataArray, 0, dataArray.Length); 289 | fs.Flush(); 290 | } 291 | } 292 | return saveFile; 293 | } 294 | 295 | /// 296 | /// 导出 IEnumerable 到 MemoryStream 297 | /// 298 | /// 299 | /// IEnumerable 300 | /// 列定义,默认为 null,通过反射的方式确定列名 301 | /// Sheet名称,默认 Sheet1 302 | /// 是否包含标题行,默认为true(包含) 303 | /// 304 | public static MemoryStream ExportToMemoryStream( 305 | IEnumerable data, 306 | Dictionary> columnDef = null, 307 | string sheetName = null, 308 | bool includeTitleRow = true 309 | ) 310 | { 311 | Ensure.NotNull(data, nameof(data)); 312 | var workbook = new XSSFWorkbook(); 313 | var sheet1 = workbook.CreateSheet(sheetName ?? "Sheet1"); 314 | if (columnDef == null) 315 | { 316 | var properties = typeof(T).GetProperties(); 317 | if (includeTitleRow) 318 | { 319 | //输出标题 320 | var titleRow = sheet1.CreateRow(0); 321 | var colIndex = 0; 322 | foreach (var item in properties) 323 | { 324 | titleRow.CreateCell(colIndex++).SetCellValue(item.Name); 325 | } 326 | } 327 | //输出内容 328 | var rowIndex = includeTitleRow ? 1 : 0; 329 | foreach (var tableRow in data) 330 | { 331 | var row = sheet1.CreateRow(rowIndex++); 332 | var colIndex = 0; 333 | foreach (var col in properties) 334 | { 335 | row.CreateCell(colIndex++).SetCellValue($"{col.GetValue(tableRow)}"); 336 | sheet1.AutoSizeColumn(colIndex); 337 | } 338 | } 339 | } 340 | else 341 | { 342 | if (includeTitleRow) 343 | { 344 | //输出标题 345 | var titleRow = sheet1.CreateRow(0); 346 | var colIndex = 0; 347 | foreach (var item in columnDef) 348 | { 349 | titleRow.CreateCell(colIndex++).SetCellValue(item.Key); 350 | } 351 | } 352 | 353 | //输出内容 354 | var rowIndex = includeTitleRow ? 1 : 0; 355 | foreach (var tableRow in data) 356 | { 357 | var row = sheet1.CreateRow(rowIndex++); 358 | var colIndex = 0; 359 | foreach (var col in columnDef) 360 | { 361 | row.CreateCell(colIndex++).SetCellValue($"{col.Value(tableRow)}"); 362 | sheet1.AutoSizeColumn(colIndex); 363 | } 364 | } 365 | } 366 | var ms = new MemoryStream(); 367 | workbook.Write(ms); 368 | ms.Flush(); 369 | return ms; 370 | } 371 | #endregion 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /MrHuo.Extensions/ObjectFormatter/CommonObjectFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Text; 9 | 10 | namespace MrHuo.Extensions 11 | { 12 | internal abstract class CommonObjectFormatter : ObjectFormatter 13 | { 14 | public override string FormatObject(object obj) 15 | { 16 | return new CommonObjectFormatter.Visitor(this).FormatObject(obj); 17 | } 18 | 19 | protected abstract CommonTypeNameFormatter TypeNameFormatter { get; } 20 | 21 | protected abstract CommonPrimitiveFormatter PrimitiveFormatter { get; } 22 | 23 | protected abstract string FormatRefKind(System.Reflection.ParameterInfo parameter); 24 | 25 | private sealed class Builder 26 | { 27 | private readonly StringBuilder _sb = new StringBuilder(); 28 | 29 | public void Append(char c) 30 | { 31 | this._sb.Append(c); 32 | } 33 | 34 | public void Append(string str, int start = 0, int count = 2147483647) 35 | { 36 | if (str == null) 37 | return; 38 | count = Math.Min(count, str.Length - start); 39 | this._sb.Append(str, start, count); 40 | } 41 | 42 | public void AppendGroupOpening() 43 | { 44 | this.Append('{'); 45 | } 46 | 47 | public void AppendGroupClosing() 48 | { 49 | this.Append(" }", 0, int.MaxValue); 50 | } 51 | 52 | public void AppendCollectionItemSeparator(bool isFirst) 53 | { 54 | if (isFirst) 55 | { 56 | this.Append(' '); 57 | } 58 | else 59 | { 60 | this.Append(", ", 0, int.MaxValue); 61 | } 62 | } 63 | 64 | internal void AppendInfiniteRecursionMarker() 65 | { 66 | this.AppendGroupOpening(); 67 | this.AppendCollectionItemSeparator(true); 68 | this.Append("...", 0, int.MaxValue); 69 | this.AppendGroupClosing(); 70 | } 71 | 72 | public override string ToString() 73 | { 74 | return this._sb.ToString(); 75 | } 76 | } 77 | 78 | internal class ReferenceEqualityComparer : IEqualityComparer 79 | { 80 | public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); 81 | 82 | private ReferenceEqualityComparer() 83 | { 84 | } 85 | 86 | bool IEqualityComparer.Equals(object a, object b) 87 | { 88 | return a == b; 89 | } 90 | 91 | int IEqualityComparer.GetHashCode(object a) 92 | { 93 | return ReferenceEqualityComparer.GetHashCode(a); 94 | } 95 | 96 | public static int GetHashCode(object a) 97 | { 98 | return RuntimeHelpers.GetHashCode(a); 99 | } 100 | } 101 | 102 | private sealed class Visitor 103 | { 104 | private readonly CommonObjectFormatter _formatter; 105 | private CommonPrimitiveFormatterOptions _primitiveOptions = new CommonPrimitiveFormatterOptions(); 106 | private HashSet _lazyVisitedObjects; 107 | 108 | private HashSet VisitedObjects 109 | { 110 | get 111 | { 112 | if (this._lazyVisitedObjects == null) 113 | this._lazyVisitedObjects = new HashSet(ReferenceEqualityComparer.Instance); 114 | return this._lazyVisitedObjects; 115 | } 116 | } 117 | 118 | public Visitor(CommonObjectFormatter formatter) 119 | { 120 | this._formatter = formatter; 121 | } 122 | 123 | public string FormatObject(object obj) 124 | { 125 | try 126 | { 127 | return this.FormatObjectRecursive(new CommonObjectFormatter.Builder(), obj, true).ToString(); 128 | } 129 | catch (InsufficientExecutionStackException ex) 130 | { 131 | return ex.ToString(); 132 | } 133 | } 134 | 135 | private CommonObjectFormatter.Builder FormatObjectRecursive( 136 | CommonObjectFormatter.Builder result, 137 | object obj, 138 | bool isRoot) 139 | { 140 | string str = this._formatter.PrimitiveFormatter.FormatPrimitive(obj, this._primitiveOptions); 141 | if (str != null) 142 | { 143 | result.Append(str, 0, int.MaxValue); 144 | return result; 145 | } 146 | Type type = obj.GetType(); 147 | System.Reflection.TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type); 148 | if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == (object)typeof(KeyValuePair<,>)) 149 | { 150 | if (isRoot) 151 | { 152 | result.Append(this._formatter.TypeNameFormatter.FormatTypeName(type), 0, int.MaxValue); 153 | result.Append(' '); 154 | } 155 | this.FormatKeyValuePair(result, obj); 156 | return result; 157 | } 158 | if (typeInfo.IsArray) 159 | { 160 | if (this.VisitedObjects.Add(obj)) 161 | { 162 | this.FormatArray(result, (Array)obj); 163 | this.VisitedObjects.Remove(obj); 164 | } 165 | else 166 | result.AppendInfiniteRecursionMarker(); 167 | return result; 168 | } 169 | bool flag = false; 170 | ICollection collection = null; 171 | if (obj is ICollection) 172 | { 173 | collection = (ICollection)obj; 174 | this.FormatCollectionHeader(result, collection); 175 | } 176 | else if (ObjectFormatterHelpers.HasOverriddenToString(typeInfo)) 177 | { 178 | this.ObjectToString(result, obj); 179 | flag = true; 180 | } 181 | else 182 | result.Append(this._formatter.TypeNameFormatter.FormatTypeName(type), 0, int.MaxValue); 183 | 184 | if (!flag) 185 | this.FormatMembers(result, obj); 186 | return result; 187 | } 188 | 189 | private void FormatMembers( 190 | CommonObjectFormatter.Builder result, 191 | object obj) 192 | { 193 | RuntimeHelpers.EnsureSufficientExecutionStack(); 194 | result.Append(' '); 195 | if (!this.VisitedObjects.Add(obj)) 196 | { 197 | result.AppendInfiniteRecursionMarker(); 198 | } 199 | else 200 | { 201 | bool flag = false; 202 | if (obj is IDictionary dict) 203 | { 204 | this.FormatDictionaryMembers(result, dict); 205 | flag = true; 206 | } 207 | else if (obj is IEnumerable sequence) 208 | { 209 | this.FormatSequenceMembers(result, sequence); 210 | flag = true; 211 | } 212 | if (!flag) 213 | this.FormatObjectMembers(result, obj); 214 | this.VisitedObjects.Remove(obj); 215 | } 216 | } 217 | 218 | private void FormatObjectMembers( 219 | CommonObjectFormatter.Builder result, 220 | object obj) 221 | { 222 | List result1 = new List(); 223 | this.FormatObjectMembersRecursive(result1, obj); 224 | bool flag = CommonObjectFormatter.Visitor.UseCollectionFormat(result1, IntrospectionExtensions.GetTypeInfo(obj.GetType())); 225 | result.AppendGroupOpening(); 226 | for (int index = 0; index < result1.Count; ++index) 227 | { 228 | result.AppendCollectionItemSeparator(index == 0); 229 | if (flag) 230 | result1[index].AppendAsCollectionEntry(result); 231 | else 232 | result1[index].Append(result, "="); 233 | } 234 | result.AppendGroupClosing(); 235 | } 236 | 237 | private static bool UseCollectionFormat( 238 | IEnumerable members, 239 | System.Reflection.TypeInfo originalType) 240 | { 241 | if (IntrospectionExtensions.GetTypeInfo(typeof(IEnumerable)).IsAssignableFrom(originalType)) 242 | return Enumerable.All(members, member => member.Index >= 0); 243 | return false; 244 | } 245 | 246 | private void FormatObjectMembersRecursive( 247 | List result, 248 | object obj) 249 | { 250 | List memberInfoList = new List(); 251 | Type baseType; 252 | for (System.Reflection.TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(obj.GetType()); 253 | typeInfo != null; 254 | typeInfo = (object)baseType != null ? IntrospectionExtensions.GetTypeInfo(baseType) : null) 255 | { 256 | memberInfoList.AddRange(Enumerable.Where(typeInfo.DeclaredFields, f => !f.IsStatic)); 257 | memberInfoList.AddRange(Enumerable.Where(typeInfo.DeclaredProperties, f => 258 | { 259 | if ((object)f.GetMethod != null) 260 | return !f.GetMethod.IsStatic; 261 | return false; 262 | })); 263 | baseType = typeInfo.BaseType; 264 | } 265 | memberInfoList.Sort((x, y) => 266 | { 267 | int num = StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name); 268 | if (num == 0) 269 | num = StringComparer.Ordinal.Compare(x.Name, y.Name); 270 | return num; 271 | }); 272 | foreach (MemberInfo member in memberInfoList) 273 | { 274 | bool flag1 = false; 275 | bool flag2 = false; 276 | if (member is FieldInfo fieldInfo) 277 | { 278 | if (!(flag2) && !fieldInfo.IsPublic && (!fieldInfo.IsFamily && !fieldInfo.IsFamilyOrAssembly)) 279 | continue; 280 | } 281 | else 282 | { 283 | PropertyInfo propertyInfo = (PropertyInfo)member; 284 | MethodInfo getMethod = propertyInfo.GetMethod; 285 | if ((object)getMethod != null) 286 | { 287 | MethodInfo setMethod = propertyInfo.SetMethod; 288 | if (!(flag2) && !getMethod.IsPublic && (!getMethod.IsFamily && !getMethod.IsFamilyOrAssembly) && ((object)setMethod == null || !setMethod.IsPublic && !setMethod.IsFamily && !setMethod.IsFamilyOrAssembly) || getMethod.GetParameters().Length != 0) 289 | continue; 290 | } 291 | else 292 | continue; 293 | } 294 | Exception exception; 295 | object memberValue = ObjectFormatterHelpers.GetMemberValue(member, obj, out exception); 296 | if (exception != null) 297 | { 298 | CommonObjectFormatter.Builder result1 = new Builder(); 299 | this.FormatException(result1, exception); 300 | if (!this.AddMember(result, new CommonObjectFormatter.Visitor.FormattedMember(-1, member.Name, result1.ToString()))) 301 | break; 302 | } 303 | else if (flag1) 304 | { 305 | if (memberValue != null && !this.VisitedObjects.Contains(memberValue)) 306 | { 307 | if (memberValue is Array array) 308 | { 309 | int index = 0; 310 | foreach (object obj1 in array) 311 | { 312 | CommonObjectFormatter.Builder result1 = new Builder(); 313 | this.FormatObjectRecursive(result1, obj1, false); 314 | if (!this.AddMember(result, new CommonObjectFormatter.Visitor.FormattedMember(index, "", result1.ToString()))) 315 | return; 316 | ++index; 317 | } 318 | } 319 | else if (this._formatter.PrimitiveFormatter.FormatPrimitive(memberValue, this._primitiveOptions) == null && this.VisitedObjects.Add(memberValue)) 320 | { 321 | this.FormatObjectMembersRecursive(result, memberValue); 322 | this.VisitedObjects.Remove(memberValue); 323 | } 324 | } 325 | } 326 | else 327 | { 328 | CommonObjectFormatter.Builder result1 = new Builder(); 329 | this.FormatObjectRecursive(result1, memberValue, false); 330 | if (!this.AddMember(result, new CommonObjectFormatter.Visitor.FormattedMember(-1, "", result1.ToString()))) 331 | break; 332 | } 333 | } 334 | } 335 | 336 | private bool AddMember( 337 | List members, 338 | CommonObjectFormatter.Visitor.FormattedMember member) 339 | { 340 | members.Add(member); 341 | return true; 342 | } 343 | 344 | private void FormatException(CommonObjectFormatter.Builder result, Exception exception) 345 | { 346 | result.Append("!<", 0, int.MaxValue); 347 | result.Append(this._formatter.TypeNameFormatter.FormatTypeName(((object)exception).GetType()), 0, int.MaxValue); 348 | result.Append('>'); 349 | } 350 | 351 | private void FormatKeyValuePair(CommonObjectFormatter.Builder result, object obj) 352 | { 353 | System.Reflection.TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(obj.GetType()); 354 | object obj1 = typeInfo.GetDeclaredProperty("Key").GetValue(obj, Array.Empty()); 355 | object obj2 = typeInfo.GetDeclaredProperty("Value").GetValue(obj, Array.Empty()); 356 | result.AppendGroupOpening(); 357 | result.AppendCollectionItemSeparator(true); 358 | this.FormatObjectRecursive(result, obj1, false); 359 | result.AppendCollectionItemSeparator(false); 360 | this.FormatObjectRecursive(result, obj2, false); 361 | result.AppendGroupClosing(); 362 | } 363 | 364 | private void FormatCollectionHeader( 365 | CommonObjectFormatter.Builder result, 366 | ICollection collection) 367 | { 368 | if (collection is Array arrayOpt) 369 | { 370 | result.Append(this._formatter.TypeNameFormatter.FormatArrayTypeName(arrayOpt.GetType(), arrayOpt), 0, int.MaxValue); 371 | } 372 | else 373 | { 374 | result.Append(this._formatter.TypeNameFormatter.FormatTypeName(collection.GetType()), 0, int.MaxValue); 375 | try 376 | { 377 | result.Append('('); 378 | result.Append(collection.Count.ToString(), 0, int.MaxValue); 379 | result.Append(')'); 380 | } 381 | catch (Exception ex) 382 | { 383 | } 384 | } 385 | } 386 | 387 | private void FormatArray(CommonObjectFormatter.Builder result, Array array) 388 | { 389 | this.FormatCollectionHeader(result, array); 390 | if (array.Rank > 1) 391 | { 392 | this.FormatMultidimensionalArrayElements(result, array); 393 | } 394 | else 395 | { 396 | result.Append(' '); 397 | this.FormatSequenceMembers(result, array); 398 | } 399 | } 400 | 401 | private void FormatDictionaryMembers( 402 | CommonObjectFormatter.Builder result, 403 | IDictionary dict) 404 | { 405 | result.AppendGroupOpening(); 406 | int num = 0; 407 | try 408 | { 409 | IDictionaryEnumerator enumerator = dict.GetEnumerator(); 410 | using (enumerator as IDisposable) 411 | { 412 | while (enumerator.MoveNext()) 413 | { 414 | DictionaryEntry entry = enumerator.Entry; 415 | result.AppendCollectionItemSeparator(num == 0); 416 | result.AppendGroupOpening(); 417 | result.AppendCollectionItemSeparator(true); 418 | this.FormatObjectRecursive(result, entry.Key, false); 419 | result.AppendCollectionItemSeparator(false); 420 | this.FormatObjectRecursive(result, entry.Value, false); 421 | result.AppendGroupClosing(); 422 | ++num; 423 | } 424 | } 425 | } 426 | catch (Exception ex) 427 | { 428 | result.AppendCollectionItemSeparator(num == 0); 429 | this.FormatException(result, ex); 430 | result.Append(' '); 431 | } 432 | result.AppendGroupClosing(); 433 | } 434 | 435 | private void FormatSequenceMembers( 436 | CommonObjectFormatter.Builder result, 437 | IEnumerable sequence) 438 | { 439 | result.AppendGroupOpening(); 440 | int num = 0; 441 | try 442 | { 443 | foreach (object obj in sequence) 444 | { 445 | result.AppendCollectionItemSeparator(num == 0); 446 | this.FormatObjectRecursive(result, obj, false); 447 | ++num; 448 | } 449 | } 450 | catch (Exception ex) 451 | { 452 | result.AppendCollectionItemSeparator(num == 0); 453 | this.FormatException(result, ex); 454 | result.Append(" ...", 0, int.MaxValue); 455 | } 456 | result.AppendGroupClosing(); 457 | } 458 | 459 | private void FormatMultidimensionalArrayElements( 460 | CommonObjectFormatter.Builder result, 461 | Array array) 462 | { 463 | if (array.Length == 0) 464 | { 465 | result.AppendCollectionItemSeparator(true); 466 | result.AppendGroupOpening(); 467 | result.AppendGroupClosing(); 468 | } 469 | else 470 | { 471 | int[] numArray = new int[array.Rank]; 472 | for (int dimension = array.Rank - 1; dimension >= 0; --dimension) 473 | numArray[dimension] = array.GetLowerBound(dimension); 474 | int num1 = 0; 475 | int num2 = 0; 476 | while (true) 477 | { 478 | int dimension1 = numArray.Length - 1; 479 | while (numArray[dimension1] > array.GetUpperBound(dimension1)) 480 | { 481 | numArray[dimension1] = array.GetLowerBound(dimension1); 482 | result.AppendGroupClosing(); 483 | --num1; 484 | --dimension1; 485 | if (dimension1 < 0) 486 | return; 487 | ++numArray[dimension1]; 488 | } 489 | result.AppendCollectionItemSeparator(num2 == 0); 490 | for (int dimension2 = numArray.Length - 1; dimension2 >= 0 && numArray[dimension2] == array.GetLowerBound(dimension2); --dimension2) 491 | { 492 | result.AppendGroupOpening(); 493 | ++num1; 494 | result.AppendCollectionItemSeparator(true); 495 | } 496 | this.FormatObjectRecursive(result, array.GetValue(numArray), false); 497 | ++numArray[numArray.Length - 1]; 498 | ++num2; 499 | } 500 | } 501 | } 502 | 503 | private void ObjectToString(CommonObjectFormatter.Builder result, object obj) 504 | { 505 | try 506 | { 507 | string str = obj.ToString(); 508 | result.Append('['); 509 | result.Append(str, 0, int.MaxValue); 510 | result.Append(']'); 511 | } 512 | catch (Exception ex) 513 | { 514 | this.FormatException(result, ex); 515 | } 516 | } 517 | 518 | private struct FormattedMember 519 | { 520 | public readonly int Index; 521 | public readonly string Name; 522 | public readonly string Value; 523 | 524 | public FormattedMember(int index, string name, string value) 525 | { 526 | this.Name = name; 527 | this.Index = index; 528 | this.Value = value; 529 | } 530 | 531 | public string GetDisplayName() 532 | { 533 | return this.Name ?? "[" + this.Index.ToString() + "]"; 534 | } 535 | 536 | public bool HasKeyName() 537 | { 538 | if (this.Index >= 0 && this.Name != null && (this.Name.Length >= 2 && this.Name[0] == '[')) 539 | return this.Name[this.Name.Length - 1] == ']'; 540 | return false; 541 | } 542 | 543 | public bool AppendAsCollectionEntry(CommonObjectFormatter.Builder result) 544 | { 545 | if (this.HasKeyName()) 546 | { 547 | result.AppendGroupOpening(); 548 | result.AppendCollectionItemSeparator(true); 549 | result.Append(this.Name, 1, this.Name.Length - 2); 550 | result.AppendCollectionItemSeparator(false); 551 | result.Append(this.Value, 0, int.MaxValue); 552 | result.AppendGroupClosing(); 553 | } 554 | else 555 | result.Append(this.Value, 0, int.MaxValue); 556 | return true; 557 | } 558 | 559 | public bool Append(CommonObjectFormatter.Builder result, string separator) 560 | { 561 | result.Append(this.GetDisplayName(), 0, int.MaxValue); 562 | result.Append(separator, 0, int.MaxValue); 563 | result.Append(this.Value, 0, int.MaxValue); 564 | return true; 565 | } 566 | } 567 | } 568 | } 569 | } 570 | --------------------------------------------------------------------------------