├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── QuanLib.BDF ├── BdfFont.cs ├── Extensions │ └── BdfExtensions.cs ├── FontData.cs └── QuanLib.BDF.csproj ├── QuanLib.BusyWaiting ├── BusyLoop.cs ├── LoopTask.cs ├── LoopTaskState.cs ├── QuanLib.BusyWaiting.csproj └── WaitTask.cs ├── QuanLib.Clipping ├── Clipboard.cs ├── ClipboardMode.cs ├── DataContainer.cs ├── DataObjectAttribute.cs ├── DataObjectConvertHandler.cs ├── DataObjectConverter.cs ├── DataObjectCreateHandler.cs ├── DataObjectFactory.cs ├── DataObjects │ ├── BitmapDataObject.cs │ ├── DataObject.cs │ ├── FileDropDataObject.cs │ ├── ImageDataObject.cs │ └── TextDataObject.cs ├── FormatTypeManager.cs ├── IClipboard.cs ├── IConvertible.cs ├── IDataContainer.cs ├── IDataObject(T).cs ├── IDataObject.cs ├── QuanLib.Clipping.csproj └── TypeConvertInfo.cs ├── QuanLib.Core ├── AccessModifier.cs ├── Attributes │ ├── DescriptionAttribute.cs │ └── NameAttribute.cs ├── ByteBitMapping.cs ├── BytesSpan.cs ├── BytesUnit.cs ├── CacheDictionary.cs ├── CheckHelper.cs ├── CollectionValidator.cs ├── CompareHelper.cs ├── CompareOperator.cs ├── DivisionResult.cs ├── EventHandler.cs ├── Events │ ├── EventArgs.cs │ └── ValueChangedEventArgs.cs ├── ExceptionBase.cs ├── Extensions │ ├── ArrayExtensions.cs │ ├── EnumExtensions.cs │ └── StreamExtensions.cs ├── FileList.cs ├── Foreach.cs ├── GenericStructs │ ├── GenericStruct(T1,T2).cs │ ├── GenericStruct(T1,T2,T3).cs │ └── GenericStruct(T1,T2,T3,T4).cs ├── HashType.cs ├── Hex32.cs ├── IBindable.cs ├── IDataModel.cs ├── IDataModelOwner.cs ├── ILogger.cs ├── ILoggerGetter.cs ├── IRunnable.cs ├── ISingleton.cs ├── IndexRange.cs ├── InstantiateArgs.cs ├── Mapping.cs ├── MemberType.cs ├── NetworkUtil.cs ├── NullValidator.cs ├── NullableAttribute.cs ├── NumberUtil.cs ├── ObjectFormatter.cs ├── ParseHandler.cs ├── Parser.cs ├── ParserBuilder.cs ├── PathType.cs ├── Platforms.cs ├── ProgressBar.cs ├── Proportion.cs ├── Proxys │ └── TextWriterProxy.cs ├── QuanLib.Core.csproj ├── QueueTimer.cs ├── ReflectionUtil.cs ├── RunnableBase.cs ├── SerializationMemberInfo.cs ├── Synchronized.cs ├── ThreadOptions.cs ├── ThrowHelper.cs ├── TimeUnit.cs ├── TryParseHandler.cs ├── UnmanagedBase.cs ├── UnmanagedRunnable.cs ├── ValidationHelper.cs └── ValueRange.cs ├── QuanLib.DataAnnotations ├── AllowedValuesIfAttribute.cs ├── CompareValidationAttribute.cs ├── ConditionalValidationAttribute.cs ├── DeniedValuesIfAttribute.cs ├── DirectoryExistsAttribute.cs ├── EqualsAttribute.cs ├── ErrorMessageHelper.cs ├── FileExistsAttribute.cs ├── GreaterThanAttribute.cs ├── GreaterThanOrEqualsAttribute.cs ├── LessThanAttribute.cs ├── LessThanOrEqualsAttribute.cs ├── NewAllowedValuesAttribute.cs ├── NewDeniedValuesAttribute.cs ├── NotEqualsAttribute.cs ├── PropertyContext.cs ├── PropertyValidationAttribute.cs ├── QuanLib.DataAnnotations.csproj └── RequiredIfAttribute.cs ├── QuanLib.Downloader ├── DownloadManager.cs ├── DownloadTask.cs ├── DownloaderExtension.cs └── QuanLib.Downloader.csproj ├── QuanLib.Excel ├── ApplicationExtension.cs ├── ExcelUtil.cs ├── QuanLib.Excel.csproj ├── RangeExtension.cs ├── WorkbookExtension.cs └── WorksheetExtension.cs ├── QuanLib.Game ├── Bounds.cs ├── CoordinateAxis.cs ├── Direction.cs ├── Facing.cs ├── FacingUtil.cs ├── IPlane.cs ├── IVector2.cs ├── IVector3.cs ├── Plane.cs ├── PlaneAxis.cs ├── PlaneFacing.cs ├── QuanLib.Game.csproj ├── Rotation.cs ├── Vector2.cs ├── Vector2Util.cs ├── Vector3.cs └── Vector3Util.cs ├── QuanLib.IO ├── BytesWriteTask.cs ├── CombineHelper.cs ├── DirectoryUtil.cs ├── Extensions │ ├── DirectoryInfoExtensions.cs │ └── PathExtensions.cs ├── FileSystem │ ├── ContainerNode.cs │ ├── DeviceNode.cs │ ├── DirectoryNode.cs │ ├── FIleNode.cs │ └── Node.cs ├── FileUtil.cs ├── FileWriteQueue.cs ├── HashUtil.cs ├── ITextListener.cs ├── LinesWriteTask.cs ├── PollingFileListener.cs ├── PollingTextFileListener.cs ├── QuanLib.IO.csproj ├── StreamWriteQueue.cs ├── TextWriteTask.cs ├── WriteTask.cs └── Zip │ ├── ZipItem.cs │ └── ZipPack.cs ├── QuanLib.Logging ├── Log4NetLogger.cs ├── LogManager.cs ├── LoggerGetter.cs └── QuanLib.Logging.csproj ├── QuanLib.TextFormat ├── AbbreviationBytesUnitText.cs ├── AbbreviationTimeUnitText.cs ├── BytesFormatText.cs ├── BytesFormatter.cs ├── ChineseBytesUnitText.cs ├── ChineseTimeUnitText.cs ├── EnglishBytesUnitText.cs ├── EnglishTimeUnitText.cs ├── QuanLib.TextFormat.csproj ├── TextFormat.cs ├── TimeFormatter.cs └── TimeUnitText.cs ├── QuanLib.TomlConfig ├── QuanLib.TomlConfig.csproj └── TomlConfigBuilder.cs ├── QuanLib.VisualObject ├── ConstructorView.cs ├── FieldView.cs ├── MemberValue.cs ├── MethodView.cs ├── ParameterView.cs ├── PropertyView.cs ├── QuanLib.VisualObject.csproj └── TypeView.cs ├── QuanLib.sln └── README.md /.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 | -------------------------------------------------------------------------------- /QuanLib.BDF/Extensions/BdfExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.BDF.Extensions 8 | { 9 | public static class BdfExtensions 10 | { 11 | public static int GetLeftLayoutMaxCount(this BdfFont bdfFont, int maxWidth, string value) 12 | { 13 | ArgumentNullException.ThrowIfNull(bdfFont, nameof(bdfFont)); 14 | ArgumentNullException.ThrowIfNull(value, nameof(value)); 15 | 16 | int width = 0; 17 | for (int i = 0; i < value.Length; i++) 18 | { 19 | width += bdfFont[value[i]].Width; 20 | if (width == maxWidth) 21 | return i + 1; 22 | else if (width > maxWidth) 23 | return i; 24 | } 25 | return width; 26 | } 27 | 28 | public static int GetRightLayoutMaxCount(this BdfFont bdfFont, int maxWidth, string value) 29 | { 30 | ArgumentNullException.ThrowIfNull(bdfFont, nameof(bdfFont)); 31 | ArgumentNullException.ThrowIfNull(value, nameof(value)); 32 | 33 | int width = 0; 34 | for (int i = value.Length - 1; i >= 0; i--) 35 | { 36 | width += bdfFont[value[i]].Width; 37 | if (width == maxWidth) 38 | return value.Length - i + 1; 39 | else if (width > maxWidth) 40 | return value.Length - i; 41 | } 42 | return width; 43 | } 44 | 45 | public static int GetTopLayoutMaxCount(this BdfFont bdfFont, int maxHeight, string value) 46 | { 47 | ArgumentNullException.ThrowIfNull(bdfFont, nameof(bdfFont)); 48 | ArgumentNullException.ThrowIfNull(value, nameof(value)); 49 | 50 | int height = 0; 51 | for (int i = 0; i < value.Length; i++) 52 | { 53 | height += bdfFont[value[i]].Height; 54 | if (height == maxHeight) 55 | return i + 1; 56 | else if (height > maxHeight) 57 | return i; 58 | } 59 | return height; 60 | } 61 | 62 | public static int GetBottomLayoutMaxCount(this BdfFont bdfFont, int maxHeight, string value) 63 | { 64 | ArgumentNullException.ThrowIfNull(bdfFont, nameof(bdfFont)); 65 | ArgumentNullException.ThrowIfNull(value, nameof(value)); 66 | 67 | int height = 0; 68 | for (int i = value.Length - 1; i >= 0; i--) 69 | { 70 | height += bdfFont[value[i]].Height; 71 | if (height == maxHeight) 72 | return value.Length - i + 1; 73 | else if (height > maxHeight) 74 | return value.Length - i; 75 | } 76 | return height; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /QuanLib.BDF/FontData.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using SixLabors.ImageSharp; 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.BDF 11 | { 12 | public class FontData 13 | { 14 | public FontData(char @char, int width, int height, int xOffset, int yOffset, BitArray bits) 15 | { 16 | ArgumentNullException.ThrowIfNull(bits, nameof(bits)); 17 | if (bits.Count != width * height) 18 | throw new ArgumentException("BitArray的位数应该为" + width * height); 19 | 20 | Char = @char; 21 | Width = width; 22 | Height = height; 23 | XOffset = xOffset; 24 | YOffset = yOffset; 25 | _bits = bits; 26 | } 27 | 28 | private readonly BitArray _bits; 29 | 30 | public char Char { get; } 31 | 32 | public int Width { get; } 33 | 34 | public int Height { get; } 35 | 36 | public int XOffset { get; } 37 | 38 | public int YOffset { get; } 39 | 40 | public bool[,] GetBitArray(bool isNegative = false) 41 | { 42 | bool[,] result = new bool[Width, Height]; 43 | Func get = isNegative ? ((x, y) => !_bits[y * Width + x]) : ((x, y) => _bits[y * Width + x]); 44 | 45 | for (int y = 0; y < Height; y++) 46 | for (int x = 0; x < Width; x++) 47 | result[x, y] = get(x, y); 48 | 49 | return result; 50 | } 51 | 52 | public bool[,] GetBitArray(int pixelSize, bool isNegative = false) 53 | { 54 | ThrowHelper.ArgumentOutOfMin(1, pixelSize, nameof(pixelSize)); 55 | 56 | if (pixelSize == 1) 57 | return GetBitArray(isNegative); 58 | 59 | Size size = new(Width * pixelSize, Height * pixelSize); 60 | bool[,] result = new bool[size.Width, size.Height]; 61 | Func get = isNegative ? ((x, y) => !_bits[y * Width + x]) : ((x, y) => _bits[y * Width + x]); 62 | 63 | for (int y1 = 0, y2 = 0; y1 < Height; y1++, y2 += pixelSize) 64 | { 65 | for (int x1 = 0, x2 = 0; x1 < Width; x1++, x2 += pixelSize) 66 | { 67 | if (get(x1, y1)) 68 | { 69 | int yend = y2 + pixelSize; 70 | int xend = x2 + pixelSize; 71 | for (int y3 = y2; y3 < yend; y3++) 72 | for (int x3 = x2; x3 < xend; x3++) 73 | result[x3, y3] = true; 74 | } 75 | } 76 | } 77 | 78 | return result; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /QuanLib.BDF/QuanLib.BDF.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.BusyWaiting/LoopTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.BusyWaiting 8 | { 9 | public class LoopTask 10 | { 11 | public LoopTask(Action action) 12 | { 13 | ArgumentNullException.ThrowIfNull(action, nameof(action)); 14 | 15 | _action = action; 16 | _semaphore = new(0); 17 | _task = WaitSemaphoreAsync(); 18 | State = LoopTaskState.NotStarted; 19 | } 20 | 21 | private readonly SemaphoreSlim _semaphore; 22 | 23 | private readonly Task _task; 24 | 25 | private readonly Action _action; 26 | 27 | public LoopTaskState State { get; private set; } 28 | 29 | public Exception? Exception { get; private set; } 30 | 31 | internal void Start() 32 | { 33 | try 34 | { 35 | State = LoopTaskState.Running; 36 | _action.Invoke(); 37 | State = LoopTaskState.Completed; 38 | } 39 | catch (Exception ex) 40 | { 41 | Exception = ex; 42 | State = LoopTaskState.Failed; 43 | } 44 | finally 45 | { 46 | _semaphore.Release(); 47 | } 48 | } 49 | 50 | public async Task WaitForCompleteAsync() 51 | { 52 | await _task; 53 | } 54 | 55 | private async Task WaitSemaphoreAsync() 56 | { 57 | await _semaphore.WaitAsync(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /QuanLib.BusyWaiting/LoopTaskState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.BusyWaiting 8 | { 9 | public enum LoopTaskState 10 | { 11 | NotStarted, 12 | 13 | Running, 14 | 15 | Completed, 16 | 17 | Failed 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.BusyWaiting/QuanLib.BusyWaiting.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.BusyWaiting/WaitTask.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.BusyWaiting 9 | { 10 | public class WaitTask 11 | { 12 | public WaitTask(BusyLoop owner, Func expression) 13 | { 14 | ArgumentNullException.ThrowIfNull(expression, nameof(expression)); 15 | ArgumentNullException.ThrowIfNull(owner, nameof(owner)); 16 | 17 | _owner = owner; 18 | _expression = expression; 19 | _waitSemaphore = new(0); 20 | _waitTask = WaitSemaphoreAsync(); 21 | } 22 | 23 | private readonly BusyLoop _owner; 24 | 25 | private readonly Func _expression; 26 | 27 | private readonly SemaphoreSlim _waitSemaphore; 28 | 29 | private readonly Task _waitTask; 30 | 31 | internal bool CheckExpression() 32 | { 33 | try 34 | { 35 | if (!_waitTask.IsCompleted && _expression.Invoke()) 36 | { 37 | _waitSemaphore.Release(); 38 | return true; 39 | } 40 | else if (!_owner.IsRunning) 41 | { 42 | _waitSemaphore.Release(); 43 | return false; 44 | } 45 | else 46 | { 47 | return false; 48 | } 49 | } 50 | catch 51 | { 52 | _waitSemaphore.Release(); 53 | return false; 54 | } 55 | } 56 | 57 | public async Task WaitForSuccessAsync() 58 | { 59 | await _waitTask; 60 | } 61 | 62 | private async Task WaitSemaphoreAsync() 63 | { 64 | await _waitSemaphore.WaitAsync(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /QuanLib.Clipping/Clipboard.cs: -------------------------------------------------------------------------------- 1 | using SixLabors.ImageSharp; 2 | using SixLabors.ImageSharp.PixelFormats; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Clipping 10 | { 11 | public class Clipboard : IClipboard 12 | { 13 | public Clipboard() 14 | { 15 | _dataContainers = []; 16 | } 17 | 18 | private readonly List _dataContainers; 19 | 20 | public ClipboardMode GetClipboardMode() 21 | { 22 | return GetDataContainer()?.ClipboardMode ?? ClipboardMode.None; 23 | } 24 | 25 | public IDataObject? GetDataObject() 26 | { 27 | return GetDataContainer()?.GetDataObject(); 28 | } 29 | 30 | public object? GetData() 31 | { 32 | return GetDataContainer()?.GetData(); 33 | } 34 | 35 | public object? GetData(string format) 36 | { 37 | return GetDataContainer()?.GetData(format); 38 | } 39 | 40 | public object? GetData(string format, bool autoConvert) 41 | { 42 | return GetDataContainer()?.GetData(format, autoConvert); 43 | } 44 | 45 | public string? GetText() 46 | { 47 | return GetDataContainer()?.GetText(); 48 | } 49 | 50 | public Image? GetImage() 51 | { 52 | return GetDataContainer()?.GetImage(); 53 | } 54 | 55 | public Image? GetBitmap() 56 | { 57 | return GetDataContainer()?.GetBitmap(); 58 | } 59 | 60 | public string[]? GetFileDrop() 61 | { 62 | return GetDataContainer()?.GetFileDrop(); 63 | } 64 | 65 | public void SetDataObject(IDataObject dataObject, ClipboardMode clipboardMode = ClipboardMode.None) 66 | { 67 | _dataContainers.Add(new(dataObject, clipboardMode)); 68 | } 69 | 70 | public void SetData(string format, object data, ClipboardMode clipboardMode = ClipboardMode.None) 71 | { 72 | _dataContainers.Add(DataContainer.CreateData(format, data, clipboardMode)); 73 | } 74 | 75 | public void SetText(string text, ClipboardMode clipboardMode = ClipboardMode.None) 76 | { 77 | _dataContainers.Add(DataContainer.CreateText(text, clipboardMode)); 78 | } 79 | 80 | public void SetImage(Image image, ClipboardMode clipboardMode = ClipboardMode.None) 81 | { 82 | _dataContainers.Add(DataContainer.CreateImage(image, clipboardMode)); 83 | } 84 | 85 | public void SetBitmap(Image image, ClipboardMode clipboardMode = ClipboardMode.None) 86 | { 87 | _dataContainers.Add(DataContainer.CreateBitmap(image, clipboardMode)); 88 | } 89 | 90 | public void SetFileDrop(string[] paths, ClipboardMode clipboardMode = ClipboardMode.None) 91 | { 92 | _dataContainers.Add(DataContainer.CreateFileDrop(paths, clipboardMode)); 93 | } 94 | 95 | public void Clear() 96 | { 97 | DataContainer[] dataContainers = _dataContainers.ToArray(); 98 | _dataContainers.Clear(); 99 | 100 | foreach (DataContainer dataContainer in dataContainers) 101 | { 102 | if (dataContainer.GetDataObject() is IDisposable disposable) 103 | disposable.Dispose(); 104 | } 105 | } 106 | 107 | private DataContainer? GetDataContainer() 108 | { 109 | if (_dataContainers.Count > 0) 110 | return _dataContainers[^1]; 111 | else 112 | return null; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /QuanLib.Clipping/ClipboardMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public enum ClipboardMode 10 | { 11 | None, 12 | 13 | Copy, 14 | 15 | Move, 16 | 17 | Link 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjectAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 10 | public class DataObjectAttribute : Attribute 11 | { 12 | public DataObjectAttribute(string format) 13 | { 14 | ArgumentNullException.ThrowIfNull(format, nameof(format)); 15 | 16 | Format = format; 17 | } 18 | 19 | public string Format { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjectConvertHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Clipping 9 | { 10 | public class DataObjectConvertHandler 11 | { 12 | public DataObjectConvertHandler(MethodInfo convertMethod) 13 | { 14 | ArgumentNullException.ThrowIfNull(convertMethod, nameof(convertMethod)); 15 | 16 | if (!convertMethod.GetParameters().Any() || !convertMethod.ReturnType.IsAssignableTo(typeof(IDataObject))) 17 | throw new ArgumentException("MethodInfo 不是合法的 Convert 方法", nameof(convertMethod)); 18 | 19 | _convertMethod = convertMethod; 20 | } 21 | 22 | private readonly MethodInfo _convertMethod; 23 | 24 | public IDataObject Convert(IDataObject dataObject) 25 | { 26 | return _convertMethod.Invoke(dataObject, null) as IDataObject ?? throw new InvalidCastException(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjectCreateHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Clipping 9 | { 10 | public class DataObjectCreateHandler 11 | { 12 | public DataObjectCreateHandler(MethodInfo createMethod) 13 | { 14 | ArgumentNullException.ThrowIfNull(createMethod, nameof(createMethod)); 15 | 16 | ParameterInfo[] parameters = createMethod.GetParameters(); 17 | if (!createMethod.IsStatic || 18 | parameters.Length != 1 || 19 | parameters[0].ParameterType != typeof(object) || 20 | !createMethod.ReturnType.IsAssignableTo(typeof(IDataObject))) 21 | throw new ArgumentException("MethodInfo 不是合法的 Create 方法", nameof(createMethod)); 22 | 23 | _createMethod = createMethod; 24 | } 25 | 26 | private readonly MethodInfo _createMethod; 27 | 28 | public IDataObject Create(object data) 29 | { 30 | return _createMethod.Invoke(null, [data]) as IDataObject ?? throw new InvalidOperationException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjects/BitmapDataObject.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using SixLabors.ImageSharp; 3 | using SixLabors.ImageSharp.PixelFormats; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.Clipping.DataObjects 11 | { 12 | [DataObject(FORMAT)] 13 | public class BitmapDataObject : UnmanagedBase, IDataObject>, IConvertible 14 | { 15 | public const string FORMAT = "Bitmap"; 16 | 17 | public string Format => FORMAT; 18 | 19 | public BitmapDataObject(Image image) 20 | { 21 | ArgumentNullException.ThrowIfNull(image, nameof(image)); 22 | 23 | _image = image; 24 | } 25 | 26 | private readonly Image _image; 27 | 28 | public Image GetData() 29 | { 30 | return _image; 31 | } 32 | 33 | object IDataObject.GetDate() 34 | { 35 | return GetData(); 36 | } 37 | 38 | ImageDataObject IConvertible.Convert() 39 | { 40 | return new(_image); 41 | } 42 | 43 | protected override void DisposeUnmanaged() 44 | { 45 | _image.Dispose(); 46 | } 47 | 48 | public static IDataObject Create(object data) 49 | { 50 | ArgumentNullException.ThrowIfNull(data, nameof(data)); 51 | 52 | if (data is Image image) 53 | return new BitmapDataObject(image); 54 | else 55 | return new DataObject(FORMAT, data); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjects/DataObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping.DataObjects 8 | { 9 | public class DataObject : IDataObject 10 | { 11 | public DataObject(string format, object data) 12 | { 13 | ArgumentException.ThrowIfNullOrEmpty(format, nameof(format)); 14 | ArgumentNullException.ThrowIfNull(data, nameof(data)); 15 | 16 | Format = format; 17 | _data = data; 18 | } 19 | 20 | private readonly object _data; 21 | 22 | public string Format { get; } 23 | 24 | public object GetData() 25 | { 26 | return _data; 27 | } 28 | 29 | object IDataObject.GetDate() 30 | { 31 | return GetData(); 32 | } 33 | 34 | public static IDataObject Create(object data) 35 | { 36 | throw new NotImplementedException(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjects/FileDropDataObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping.DataObjects 8 | { 9 | [DataObject(FORMAT)] 10 | public class FileDropDataObject : IDataObject, IConvertible 11 | { 12 | public const string FORMAT = "FileDrop"; 13 | 14 | public FileDropDataObject(params string[] paths) 15 | { 16 | ArgumentNullException.ThrowIfNull(paths, nameof(paths)); 17 | 18 | _paths = paths; 19 | } 20 | 21 | private readonly string[] _paths; 22 | 23 | public string Format => FORMAT; 24 | 25 | public string[] GetData() 26 | { 27 | return _paths; 28 | } 29 | 30 | object IDataObject.GetDate() 31 | { 32 | return GetData(); 33 | } 34 | 35 | TextDataObject IConvertible.Convert() 36 | { 37 | return new(ToString()); 38 | } 39 | 40 | public override string ToString() 41 | { 42 | if (_paths.Length == 0) 43 | { 44 | return string.Empty; 45 | } 46 | else if (_paths.Where(w => w.Contains(' ')).Any()) 47 | { 48 | return string.Join(',', _paths.Select(s => $"\"{s}\"")); 49 | } 50 | else 51 | { 52 | return string.Join(',', _paths); 53 | } 54 | } 55 | 56 | public static IDataObject Create(object data) 57 | { 58 | ArgumentNullException.ThrowIfNull(data, nameof(data)); 59 | 60 | if (data is string[] paths) 61 | return new FileDropDataObject(paths); 62 | else 63 | return new DataObject(FORMAT, data); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjects/ImageDataObject.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using SixLabors.ImageSharp; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Clipping.DataObjects 10 | { 11 | [DataObject(FORMAT)] 12 | public class ImageDataObject : UnmanagedBase, IDataObject 13 | { 14 | public const string FORMAT = "Image"; 15 | 16 | public ImageDataObject(Image image) 17 | { 18 | ArgumentNullException.ThrowIfNull(image, nameof(image)); 19 | 20 | _image = image; 21 | } 22 | 23 | private readonly Image _image; 24 | 25 | public string Format => FORMAT; 26 | 27 | public Image GetData() 28 | { 29 | return _image; 30 | } 31 | 32 | object IDataObject.GetDate() 33 | { 34 | return GetData(); 35 | } 36 | 37 | protected override void DisposeUnmanaged() 38 | { 39 | _image.Dispose(); 40 | } 41 | 42 | public static IDataObject Create(object data) 43 | { 44 | ArgumentNullException.ThrowIfNull(data, nameof(data)); 45 | 46 | if (data is Image image) 47 | return new ImageDataObject(image); 48 | else 49 | return new DataObject(FORMAT, data); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /QuanLib.Clipping/DataObjects/TextDataObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping.DataObjects 8 | { 9 | [DataObject(FORMAT)] 10 | public class TextDataObject : IDataObject 11 | { 12 | public const string FORMAT = "Text"; 13 | 14 | public TextDataObject(string text) 15 | { 16 | ArgumentNullException.ThrowIfNull(text, nameof(text)); 17 | 18 | _text = text; 19 | } 20 | 21 | private readonly string _text; 22 | 23 | public string Format => FORMAT; 24 | 25 | public string GetData() 26 | { 27 | return _text; 28 | } 29 | 30 | object IDataObject.GetDate() 31 | { 32 | return GetData(); 33 | } 34 | 35 | public static IDataObject Create(object data) 36 | { 37 | ArgumentNullException.ThrowIfNull(data, nameof(data)); 38 | 39 | if (data is string text) 40 | return new TextDataObject(text); 41 | else 42 | return new DataObject(FORMAT, data); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /QuanLib.Clipping/FormatTypeManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.Clipping 11 | { 12 | public static class FormatTypeManager 13 | { 14 | static FormatTypeManager() 15 | { 16 | RegisterFormAssembly(Assembly.GetExecutingAssembly()); 17 | } 18 | 19 | private static readonly ConcurrentDictionary _formatTypeMap = []; 20 | 21 | private static readonly Type _dataObjectType = typeof(IDataObject); 22 | 23 | public static ICollection Formats => _formatTypeMap.Keys; 24 | 25 | public static void Register(string format, Type type) 26 | { 27 | ArgumentException.ThrowIfNullOrEmpty(format, nameof(format)); 28 | ArgumentNullException.ThrowIfNull(type, nameof(type)); 29 | 30 | if (!type.IsAssignableTo(_dataObjectType)) 31 | throw new ArgumentException("Type类型未实现 IDataObject 接口", nameof(type)); 32 | 33 | if (_formatTypeMap.ContainsKey(format) || _formatTypeMap.Values.Where((w => w == type)).Any()) 34 | throw new ArgumentException("已存在相同的键或值"); 35 | 36 | _formatTypeMap.TryAdd(format, type); 37 | } 38 | 39 | public static void RegisterFormAssembly(Assembly assembly) 40 | { 41 | ArgumentNullException.ThrowIfNull(assembly, nameof(assembly)); 42 | 43 | foreach (Type type in assembly.GetTypes()) 44 | { 45 | DataObjectAttribute? dataObjectAttribute = type.GetCustomAttribute(); 46 | if (dataObjectAttribute is null) 47 | continue; 48 | 49 | if (!type.IsAssignableTo(_dataObjectType)) 50 | continue; 51 | 52 | if (_formatTypeMap.ContainsKey(dataObjectAttribute.Format) || _formatTypeMap.Values.Where((w => w == type)).Any()) 53 | continue; 54 | 55 | _formatTypeMap.TryAdd(dataObjectAttribute.Format, type); 56 | } 57 | } 58 | 59 | public static bool TryGetType(string format, [MaybeNullWhen(false)] out Type type) 60 | { 61 | return _formatTypeMap.TryGetValue(format, out type); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /QuanLib.Clipping/IClipboard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public interface IClipboard 10 | { 11 | public ClipboardMode GetClipboardMode(); 12 | 13 | public IDataObject? GetDataObject(); 14 | 15 | public object? GetData(); 16 | 17 | public object? GetData(string format); 18 | 19 | public object? GetData(string format, bool autoConvert); 20 | 21 | public void SetDataObject(IDataObject dataObject, ClipboardMode clipboardMode); 22 | 23 | public void SetData(string format, object data, ClipboardMode clipboardMode); 24 | 25 | public void Clear(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuanLib.Clipping/IConvertible.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public interface IConvertible where T : IDataObject 10 | { 11 | public T Convert(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuanLib.Clipping/IDataContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public interface IDataContainer 10 | { 11 | public ClipboardMode ClipboardMode { get; } 12 | 13 | public IDataObject GetDataObject(); 14 | 15 | public object GetData(); 16 | 17 | public object? GetData(string format); 18 | 19 | public object? GetData(string format, bool autoConvert); 20 | 21 | public object? GetData(Type dataType); 22 | 23 | public object? GetData(Type dataType, bool autoConvert); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuanLib.Clipping/IDataObject(T).cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public interface IDataObject : IDataObject where T : notnull 10 | { 11 | public T GetData(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuanLib.Clipping/IDataObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public interface IDataObject 10 | { 11 | public string Format { get; } 12 | 13 | public object GetDate(); 14 | 15 | public abstract static IDataObject Create(object data); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.Clipping/QuanLib.Clipping.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.Clipping/TypeConvertInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Clipping 8 | { 9 | public readonly struct TypeConvertInfo : IEquatable 10 | { 11 | public readonly Type SourceType; 12 | 13 | public readonly Type TargetType; 14 | 15 | public TypeConvertInfo() 16 | { 17 | SourceType = typeof(object); 18 | TargetType = typeof(object); 19 | } 20 | 21 | public TypeConvertInfo(Type sourceType, Type targetType) 22 | { 23 | ArgumentNullException.ThrowIfNull(sourceType, nameof(sourceType)); 24 | ArgumentNullException.ThrowIfNull(targetType, nameof(targetType)); 25 | 26 | SourceType = sourceType; 27 | TargetType = targetType; 28 | } 29 | 30 | public bool Equals(TypeConvertInfo other) 31 | { 32 | return SourceType.Equals(other.SourceType) && TargetType.Equals(other.TargetType); 33 | } 34 | 35 | public override bool Equals(object? obj) 36 | { 37 | return obj is TypeConvertInfo other && Equals(other); 38 | } 39 | 40 | public override int GetHashCode() 41 | { 42 | return HashCode.Combine(SourceType, TargetType); 43 | } 44 | 45 | public static bool operator ==(TypeConvertInfo left, TypeConvertInfo right) 46 | { 47 | return left.Equals(right); 48 | } 49 | 50 | public static bool operator !=(TypeConvertInfo left, TypeConvertInfo right) 51 | { 52 | return !left.Equals(right); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /QuanLib.Core/AccessModifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public enum AccessModifier 10 | { 11 | Public = 6, 12 | 13 | Private = 1, 14 | 15 | Protected = 2, 16 | 17 | Internal = 4, 18 | 19 | ProtectedInternal = 5, 20 | 21 | PrivateProtected = 3, 22 | 23 | File = 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuanLib.Core/Attributes/DescriptionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)] 10 | public sealed class DescriptionAttribute : Attribute 11 | { 12 | public DescriptionAttribute(string description) 13 | { 14 | ArgumentNullException.ThrowIfNull(description, nameof(description)); 15 | 16 | Description = description; 17 | } 18 | 19 | public string Description { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /QuanLib.Core/Attributes/NameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Attributes 8 | { 9 | [AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)] 10 | public sealed class NameAttribute : Attribute 11 | { 12 | public NameAttribute(string name) 13 | { 14 | ArgumentNullException.ThrowIfNull(name, nameof(name)); 15 | 16 | Name = name; 17 | } 18 | 19 | public string Name { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /QuanLib.Core/ByteBitMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public static class ByteBitMapping 10 | { 11 | static ByteBitMapping() 12 | { 13 | _bytes = []; 14 | for (int i = byte.MinValue; i <= byte.MaxValue; i++) 15 | _bytes.Add((byte)i, NumberUtil.ToBitArray((byte)i)); 16 | 17 | _lowers = []; 18 | for (int i = byte.MinValue; i <= byte.MaxValue; i++) 19 | _lowers.Add(i.ToString("x2"), _bytes[(byte)i]); 20 | 21 | _uppers = []; 22 | for (int i = byte.MinValue; i <= byte.MaxValue; i++) 23 | _uppers.Add(i.ToString("X2"), _bytes[(byte)i]); 24 | } 25 | 26 | private static readonly Dictionary _bytes; 27 | 28 | private static readonly Dictionary _lowers; 29 | 30 | private static readonly Dictionary _uppers; 31 | 32 | public static bool[] FromByte(byte b) => Clone(_bytes[b]); 33 | 34 | public static bool[] FromLiwer(string s) => Clone(_lowers[s]); 35 | 36 | public static bool[] FromUpper(string s) => Clone(_uppers[s]); 37 | 38 | private static bool[] Clone(bool[] source) 39 | { 40 | bool[] result = new bool[source.Length]; 41 | source.CopyTo(result, 0); 42 | return result; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /QuanLib.Core/BytesUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public enum BytesUnit 10 | { 11 | B, 12 | 13 | KB, 14 | 15 | MB, 16 | 17 | GB, 18 | 19 | TB, 20 | 21 | PB, 22 | 23 | EB, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuanLib.Core/CheckHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public static class CheckHelper 10 | { 11 | public static bool Range(T min, T max, T value) where T : IComparable 12 | { 13 | return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0; 14 | } 15 | 16 | public static bool Min(T value, T min) where T : IComparable 17 | { 18 | return value.CompareTo(min) >= 0; 19 | } 20 | 21 | public static bool Max(T value, T max) where T : IComparable 22 | { 23 | return value.CompareTo(max) <= 0; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /QuanLib.Core/CollectionValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public static class CollectionValidator 11 | { 12 | public static bool TryValidateNull(IEnumerable enumerable, out int[] indexs) 13 | { 14 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 15 | 16 | List indexList = []; 17 | int index = 0; 18 | foreach (T? value in enumerable) 19 | { 20 | if (value is null) 21 | indexList.Add(index); 22 | index++; 23 | } 24 | 25 | indexs = indexList.ToArray(); 26 | return indexs.Length == 0; 27 | } 28 | 29 | public static void ValidateNull(IEnumerable enumerable, string name) 30 | { 31 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 32 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 33 | 34 | if (TryValidateNull(enumerable, out var indexs)) 35 | return; 36 | 37 | throw new ArgumentException("集合的一个或多个子项为null:" + string.Join(", ", indexs.Select(s => $"[{s}]")), name); 38 | } 39 | 40 | public static bool TryValidateNullOrEmpty(IEnumerable enumerable, out int[] indexs) 41 | { 42 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 43 | 44 | List indexList = []; 45 | int index = 0; 46 | foreach (string value in enumerable) 47 | { 48 | if (string.IsNullOrEmpty(value)) 49 | indexList.Add(index); 50 | index++; 51 | } 52 | 53 | indexs = indexList.ToArray(); 54 | return indexs.Length == 0; 55 | } 56 | 57 | public static void ValidateNullOrEmpty(IEnumerable enumerable, string name) 58 | { 59 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 60 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 61 | 62 | if (TryValidateNullOrEmpty(enumerable, out var indexs)) 63 | return; 64 | 65 | throw new ArgumentException("字符串集合的一个或多个子项为null或空:" + string.Join(", ", indexs.Select(s => $"[{s}]")), name); 66 | } 67 | 68 | public static bool TryValidateNullOrWhiteSpace(IEnumerable enumerable, out int[] indexs) 69 | { 70 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 71 | 72 | List indexList = []; 73 | int index = 0; 74 | foreach (string value in enumerable) 75 | { 76 | if (string.IsNullOrWhiteSpace(value)) 77 | indexList.Add(index); 78 | index++; 79 | } 80 | 81 | indexs = indexList.ToArray(); 82 | return indexs.Length == 0; 83 | } 84 | 85 | public static void ValidateNullOrWhiteSpace(IEnumerable enumerable, string name) 86 | { 87 | ArgumentNullException.ThrowIfNull(enumerable, nameof(enumerable)); 88 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 89 | 90 | if (TryValidateNullOrWhiteSpace(enumerable, out var indexs)) 91 | return; 92 | 93 | throw new ArgumentException("字符串集合的一个或多个子项为null或空白:" + string.Join(", ", indexs.Select(s => $"[{s}]")), name); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /QuanLib.Core/CompareHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public static class CompareHelper 10 | { 11 | public static bool CompareEqual(object? value, object? other) 12 | { 13 | return value?.GetType() == other?.GetType() && Equals(value, other); 14 | } 15 | 16 | public static bool CompareNotEqual(object? value, object? other) 17 | { 18 | return value?.GetType() == other?.GetType() && !Equals(value, other); 19 | } 20 | 21 | public static bool CompareLessThan(object? value, object? other) 22 | { 23 | if (value is IComparable ivalue && other is IComparable iother && ivalue.GetType() == iother.GetType()) 24 | { 25 | return ivalue.CompareTo(iother) < 0; 26 | } 27 | else 28 | { 29 | return false; 30 | } 31 | } 32 | 33 | public static bool CompareLessThanOrEquals(object? value, object? other) 34 | { 35 | if (value is IComparable ivalue && other is IComparable iother && ivalue.GetType() == iother.GetType()) 36 | { 37 | return ivalue.CompareTo(iother) <= 0; 38 | } 39 | else 40 | { 41 | return false; 42 | } 43 | } 44 | 45 | public static bool CompareGreaterThan(object? value, object? other) 46 | { 47 | if (value is IComparable ivalue && other is IComparable iother && ivalue.GetType() == iother.GetType()) 48 | { 49 | return ivalue.CompareTo(iother) > 0; 50 | } 51 | else 52 | { 53 | return false; 54 | } 55 | } 56 | 57 | public static bool CompareGreaterThanOrEquals(object? value, object? other) 58 | { 59 | if (value is IComparable ivalue && other is IComparable iother && ivalue.GetType() == iother.GetType()) 60 | { 61 | return ivalue.CompareTo(iother) >= 0; 62 | } 63 | else 64 | { 65 | return false; 66 | } 67 | } 68 | public static bool Compare(object? value, object? other, CompareOperator compareOperator) 69 | { 70 | return compareOperator switch 71 | { 72 | CompareOperator.Equal => CompareEqual(value, other), 73 | CompareOperator.NotEqual => CompareNotEqual(value, other), 74 | CompareOperator.LessThan => CompareLessThan(value, other), 75 | CompareOperator.LessThanOrEquals => CompareLessThanOrEquals(value, other), 76 | CompareOperator.GreaterThan => CompareGreaterThan(value, other), 77 | CompareOperator.GreaterThanOrEquals => CompareGreaterThanOrEquals(value, other), 78 | _ => throw new InvalidOperationException(), 79 | }; 80 | } 81 | 82 | 83 | public static string ToSymbol(this CompareOperator compareOperator) 84 | { 85 | return compareOperator switch 86 | { 87 | CompareOperator.Equal => "==", 88 | CompareOperator.NotEqual => "!=", 89 | CompareOperator.LessThan => "<", 90 | CompareOperator.LessThanOrEquals => "<=", 91 | CompareOperator.GreaterThan => ">", 92 | CompareOperator.GreaterThanOrEquals => ">=", 93 | _ => throw new InvalidOperationException(), 94 | }; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /QuanLib.Core/CompareOperator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public enum CompareOperator 10 | { 11 | Equal, 12 | 13 | NotEqual, 14 | 15 | LessThan, 16 | 17 | LessThanOrEquals, 18 | 19 | GreaterThan, 20 | 21 | GreaterThanOrEquals 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /QuanLib.Core/DivisionResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public readonly struct DivisionResult(int result, int remainder) 10 | { 11 | public readonly int Result = result; 12 | 13 | public readonly int Remainder = remainder; 14 | 15 | public static DivisionResult Compute(int left, int right) 16 | { 17 | int result = left / right; 18 | int remainder = right % left; 19 | return new(result, remainder); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /QuanLib.Core/EventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public delegate void EventHandler(TSender sender, TEventArgs e) where TEventArgs : EventArgs; 10 | } 11 | -------------------------------------------------------------------------------- /QuanLib.Core/Events/EventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Events 8 | { 9 | public class EventArgs(T argument) : EventArgs 10 | { 11 | public T Argument { get; } = argument; 12 | } 13 | 14 | public class EventArgs(T1 argument1, T2 argument2) : EventArgs 15 | { 16 | public T1 Argument1 { get; } = argument1; 17 | public T2 Argument2 { get; } = argument2; 18 | } 19 | 20 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3) : EventArgs 21 | { 22 | public T1 Argument1 { get; } = argument1; 23 | public T2 Argument2 { get; } = argument2; 24 | public T3 Argument3 { get; } = argument3; 25 | } 26 | 27 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3, T4 argument4) : EventArgs 28 | { 29 | public T1 Argument1 { get; } = argument1; 30 | public T2 Argument2 { get; } = argument2; 31 | public T3 Argument3 { get; } = argument3; 32 | public T4 Argument4 { get; } = argument4; 33 | } 34 | 35 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5) : EventArgs 36 | { 37 | public T1 Argument1 { get; } = argument1; 38 | public T2 Argument2 { get; } = argument2; 39 | public T3 Argument3 { get; } = argument3; 40 | public T4 Argument4 { get; } = argument4; 41 | public T5 Argument5 { get; } = argument5; 42 | } 43 | 44 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5, T6 argument6) : EventArgs 45 | { 46 | public T1 Argument1 { get; } = argument1; 47 | public T2 Argument2 { get; } = argument2; 48 | public T3 Argument3 { get; } = argument3; 49 | public T4 Argument4 { get; } = argument4; 50 | public T5 Argument5 { get; } = argument5; 51 | public T6 Argument6 { get; } = argument6; 52 | } 53 | 54 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5, T6 argument6, T7 argument7) : EventArgs 55 | { 56 | public T1 Argument1 { get; } = argument1; 57 | public T2 Argument2 { get; } = argument2; 58 | public T3 Argument3 { get; } = argument3; 59 | public T4 Argument4 { get; } = argument4; 60 | public T5 Argument5 { get; } = argument5; 61 | public T6 Argument6 { get; } = argument6; 62 | public T7 Argument7 { get; } = argument7; 63 | } 64 | 65 | public class EventArgs(T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5, T6 argument6, T7 argument7, T8 argument8) : EventArgs 66 | { 67 | public T1 Argument1 { get; } = argument1; 68 | public T2 Argument2 { get; } = argument2; 69 | public T3 Argument3 { get; } = argument3; 70 | public T4 Argument4 { get; } = argument4; 71 | public T5 Argument5 { get; } = argument5; 72 | public T6 Argument6 { get; } = argument6; 73 | public T7 Argument7 { get; } = argument7; 74 | public T8 Argument8 { get; } = argument8; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /QuanLib.Core/Events/ValueChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Events 8 | { 9 | public class ValueChangedEventArgs(T oldValue, T newValue) : EventArgs 10 | { 11 | public T OldValue { get; } = oldValue; 12 | 13 | public T NewValue { get; } = newValue; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuanLib.Core/ExceptionBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public abstract class ExceptionBase : Exception 10 | { 11 | public ExceptionBase() : base(null) 12 | { 13 | InitialMessage = DefaultMessage; 14 | } 15 | 16 | public ExceptionBase(string? messge) : base(null) 17 | { 18 | InitialMessage = messge; 19 | } 20 | 21 | public ExceptionBase(string? messge, Exception innerException) : base(null, innerException) 22 | { 23 | InitialMessage = messge; 24 | } 25 | 26 | public override string Message 27 | { 28 | get 29 | { 30 | if (!string.IsNullOrEmpty(InitialMessage)) 31 | return InitialMessage; 32 | else 33 | return DefaultMessage; 34 | } 35 | } 36 | 37 | protected virtual string? InitialMessage { get; set; } 38 | 39 | protected abstract string DefaultMessage { get; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /QuanLib.Core/Extensions/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Extensions 8 | { 9 | public static class EnumExtensions 10 | { 11 | public static T[] GetFlags(this T flags) where T : struct, Enum 12 | { 13 | List result = []; 14 | T[] values = Enum.GetValues(); 15 | 16 | foreach (T value in values) 17 | { 18 | if (flags.HasFlag(value)) 19 | result.Add(value); 20 | } 21 | 22 | return result.ToArray(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuanLib.Core/Extensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.Extensions 8 | { 9 | public static class StreamExtensions 10 | { 11 | public static string ReadAllText(this Stream stream) 12 | { 13 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 14 | return stream.ReadAllText(Encoding.UTF8); 15 | } 16 | 17 | public static string ReadAllText(this Stream stream, Encoding encoding) 18 | { 19 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 20 | ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); 21 | 22 | if (stream.CanSeek && stream.Position != 0) 23 | stream.Seek(0, SeekOrigin.Begin); 24 | 25 | using StreamReader reader = new(stream, encoding); 26 | return reader.ReadToEnd(); 27 | } 28 | 29 | public static string[] ReadAllLines(this Stream stream) 30 | { 31 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 32 | return stream.ReadAllLines(Encoding.UTF8); 33 | } 34 | 35 | public static string[] ReadAllLines(this Stream stream, Encoding encoding) 36 | { 37 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 38 | ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); 39 | 40 | if (stream.CanSeek && stream.Position != 0) 41 | stream.Seek(0, SeekOrigin.Begin); 42 | 43 | using StreamReader reader = new(stream, Encoding.UTF8); 44 | List lines = []; 45 | while (!reader.EndOfStream) 46 | { 47 | string? line = reader.ReadLine(); 48 | if (line is not null) 49 | lines.Add(line); 50 | } 51 | return lines.ToArray(); 52 | } 53 | 54 | public static void CopyTo(this Stream stream, Stream destination, long position, long length) 55 | { 56 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 57 | ArgumentNullException.ThrowIfNull(destination, nameof(destination)); 58 | 59 | if (!stream.CanSeek) 60 | throw new ArgumentException("流不支持查找", nameof(stream)); 61 | if (!stream.CanRead) 62 | throw new ArgumentException("流不支持读取", nameof(stream)); 63 | if (!destination.CanWrite) 64 | throw new ArgumentException("目标流不支持写入", nameof(destination)); 65 | 66 | ThrowHelper.ArgumentOutOfRange(0, stream.Length - 1, position, nameof(position)); 67 | ThrowHelper.ArgumentOutOfRange(0, stream.Length - position, length, nameof(length)); 68 | 69 | if (stream.Position != position) 70 | stream.Seek(position, SeekOrigin.Begin); 71 | 72 | long total = 0; 73 | byte[] buffer = new byte[4096]; 74 | do 75 | { 76 | int read = stream.Read(buffer, 0, (int)Math.Min(buffer.Length, length - total)); 77 | if (read <= 0) 78 | break; 79 | destination.Write(buffer, 0, read); 80 | total += read; 81 | } while (total < length); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /QuanLib.Core/FileList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public class FileList : IReadOnlyList 11 | { 12 | private FileList(string directory, List files, int index) 13 | { 14 | Directory = directory; 15 | _files = files; 16 | CurrentIndex = index; 17 | } 18 | 19 | private readonly List _files; 20 | 21 | public string this[int index] => _files[index]; 22 | 23 | public int Count => _files.Count; 24 | 25 | public int CurrentIndex { get; private set; } 26 | 27 | public string? CurrentFile 28 | { 29 | get 30 | { 31 | if (_files.Count == 0) 32 | return null; 33 | return _files[CurrentIndex]; 34 | } 35 | } 36 | 37 | public string Directory { get; } 38 | 39 | public bool Contains(string item) 40 | { 41 | return _files.Contains(item); 42 | } 43 | 44 | public string? GetPrevious() 45 | { 46 | if (_files.Count == 0) 47 | return null; 48 | 49 | CurrentIndex--; 50 | if (CurrentIndex < 0) 51 | CurrentIndex = _files.Count - 1; 52 | 53 | return _files[CurrentIndex]; 54 | } 55 | 56 | public string? GetNext() 57 | { 58 | if (_files.Count == 0) 59 | return null; 60 | 61 | CurrentIndex++; 62 | if (CurrentIndex >= _files.Count) 63 | CurrentIndex = 0; 64 | 65 | return _files[CurrentIndex]; 66 | } 67 | 68 | public static FileList LoadDirectory(string directory, IEnumerable extensions) 69 | { 70 | ArgumentException.ThrowIfNullOrEmpty(directory, nameof(directory)); 71 | ThrowHelper.DirectoryNotFound(directory); 72 | 73 | string[] items = System.IO.Directory.GetFiles(directory); 74 | List extensionList = new(extensions); 75 | List files = []; 76 | 77 | foreach (string item in items) 78 | { 79 | if (extensionList.Contains(Path.GetExtension(item).TrimStart('.'))) 80 | files.Add(item); 81 | } 82 | 83 | int index; 84 | if (files.Count > 0) 85 | index = 0; 86 | else 87 | index = -1; 88 | 89 | return new(directory, files, index); 90 | } 91 | 92 | public static FileList LoadFile(string file, IEnumerable extensions) 93 | { 94 | ArgumentException.ThrowIfNullOrEmpty(file, nameof(file)); 95 | ThrowHelper.FileNotFound(file); 96 | 97 | string directory = Path.GetDirectoryName(file) ?? throw new InvalidOperationException(); 98 | string[] items = System.IO.Directory.GetFiles(directory); 99 | List extensionList = new(extensions); 100 | List files = new(); 101 | 102 | foreach (string item in items) 103 | { 104 | if (extensionList.Contains(Path.GetExtension(item).TrimStart('.'))) 105 | files.Add(item); 106 | } 107 | 108 | int index = files.IndexOf(file); 109 | 110 | return new(directory, files, index); 111 | } 112 | 113 | public IEnumerator GetEnumerator() 114 | { 115 | return _files.GetEnumerator(); 116 | } 117 | 118 | IEnumerator IEnumerable.GetEnumerator() 119 | { 120 | return ((IEnumerable)_files).GetEnumerator(); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /QuanLib.Core/GenericStructs/GenericStruct(T1,T2).cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.GenericStructs 8 | { 9 | public readonly struct GenericStruct(T1 itemA, T2 itemB) : IEquatable> 10 | { 11 | public readonly T1 ItemA = itemA; 12 | public readonly T2 ItemB = itemB; 13 | 14 | public bool Equals(GenericStruct other) 15 | { 16 | return Equals(ItemA, other.ItemA) && Equals(ItemB, other.ItemB); 17 | } 18 | 19 | public override bool Equals(object? obj) 20 | { 21 | return obj is GenericStruct other && Equals(other); 22 | } 23 | 24 | public override int GetHashCode() 25 | { 26 | return HashCode.Combine(ItemA, ItemB); 27 | } 28 | 29 | public static bool operator ==(GenericStruct left, GenericStruct right) 30 | { 31 | return left.Equals(right); 32 | } 33 | 34 | public static bool operator !=(GenericStruct left, GenericStruct right) 35 | { 36 | return !left.Equals(right); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QuanLib.Core/GenericStructs/GenericStruct(T1,T2,T3).cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.GenericStructs 8 | { 9 | public readonly struct GenericStruct(T1 itemA, T2 itemB, T3 itemC) : IEquatable> 10 | { 11 | public readonly T1 ItemA = itemA; 12 | public readonly T2 ItemB = itemB; 13 | public readonly T3 ItemC = itemC; 14 | 15 | public bool Equals(GenericStruct other) 16 | { 17 | return Equals(ItemA, other.ItemA) && Equals(ItemB, other.ItemB) && Equals(ItemC, other.ItemC); 18 | } 19 | 20 | public override bool Equals(object? obj) 21 | { 22 | return obj is GenericStruct other && Equals(other); 23 | } 24 | 25 | public override int GetHashCode() 26 | { 27 | return HashCode.Combine(ItemA, ItemB, ItemC); 28 | } 29 | 30 | public static bool operator ==(GenericStruct left, GenericStruct right) 31 | { 32 | return left.Equals(right); 33 | } 34 | 35 | public static bool operator !=(GenericStruct left, GenericStruct right) 36 | { 37 | return !left.Equals(right); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /QuanLib.Core/GenericStructs/GenericStruct(T1,T2,T3,T4).cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core.GenericStructs 8 | { 9 | public readonly struct GenericStruct(T1 itemA, T2 itemB, T3 itemC, T4 itemD) : IEquatable> 10 | { 11 | public readonly T1 ItemA = itemA; 12 | public readonly T2 ItemB = itemB; 13 | public readonly T3 ItemC = itemC; 14 | public readonly T4 ItemD = itemD; 15 | 16 | public bool Equals(GenericStruct other) 17 | { 18 | return Equals(ItemA, other.ItemA) && Equals(ItemB, other.ItemB) && Equals(ItemC, other.ItemC) && Equals(ItemD, other.ItemD); 19 | } 20 | 21 | public override bool Equals(object? obj) 22 | { 23 | return obj is GenericStruct other && Equals(other); 24 | } 25 | 26 | public override int GetHashCode() 27 | { 28 | return HashCode.Combine(ItemA, ItemB, ItemC, ItemD); 29 | } 30 | 31 | public static bool operator ==(GenericStruct left, GenericStruct right) 32 | { 33 | return left.Equals(right); 34 | } 35 | 36 | public static bool operator !=(GenericStruct left, GenericStruct right) 37 | { 38 | return !left.Equals(right); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /QuanLib.Core/HashType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | /// 10 | /// 哈希算法类型 11 | /// 12 | public enum HashType 13 | { 14 | /// 15 | /// 160位SHA值 16 | /// 17 | SHA1, 18 | 19 | /// 20 | /// 256位SHA值 21 | /// 22 | SHA256, 23 | 24 | /// 25 | /// 384位SHA值 26 | /// 27 | SHA384, 28 | 29 | /// 30 | /// 512位SHA值 31 | /// 32 | SHA512, 33 | 34 | /// 35 | /// 信息摘要算法5 36 | /// 37 | MD5 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QuanLib.Core/Hex32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | /// 11 | /// 32位十六进制数 12 | /// 13 | public class Hex32 14 | { 15 | static Hex32() 16 | { 17 | ToHexMap = new(); 18 | char num = '0'; 19 | for (byte i = 0; i < 10; i++) 20 | ToHexMap.Add(i, num++); 21 | ToHexMap.Add(10, 'a'); 22 | ToHexMap.Add(11, 'b'); 23 | ToHexMap.Add(12, 'c'); 24 | ToHexMap.Add(13, 'd'); 25 | ToHexMap.Add(14, 'e'); 26 | ToHexMap.Add(15, 'f'); 27 | 28 | ToDecMap = new(); 29 | foreach (var item in ToHexMap) 30 | ToDecMap.Add(item.Value, item.Key); 31 | } 32 | 33 | public Hex32() 34 | { 35 | _hex = new byte[8]; 36 | } 37 | 38 | public Hex32(int value) 39 | { 40 | _hex = new byte[8]; 41 | 42 | string hexString = Convert.ToString(value, 16); 43 | if (hexString.Length < 8) 44 | { 45 | hexString = new string('0', 8 - hexString.Length) + hexString; 46 | } 47 | for (int i = 0; i < 8; i++) 48 | { 49 | _hex[i] = ToDecMap[hexString[7 - i]]; 50 | } 51 | } 52 | 53 | private static readonly Dictionary ToHexMap; 54 | 55 | private static readonly Dictionary ToDecMap; 56 | 57 | private byte[] _hex; 58 | 59 | public int Bit 60 | { 61 | get 62 | { 63 | for (int i = 7; i >= 0; i--) 64 | if (_hex[i] != 0) 65 | return i + 1; 66 | return 1; 67 | } 68 | } 69 | 70 | public string ToString(int length) 71 | { 72 | if (length < 0) 73 | throw new ArgumentOutOfRangeException(nameof(length), length, "字符串长度不能小于0"); 74 | 75 | if (Bit < length) 76 | return new string('0', length - Bit) + ToString(); 77 | return ToString(); 78 | } 79 | 80 | public override string ToString() 81 | { 82 | StringBuilder sb = new(); 83 | for (int i = Bit - 1; i >= 0; i--) 84 | sb.Append(ToHexMap[_hex[i]]); 85 | 86 | return sb.ToString(); 87 | } 88 | 89 | public static Hex32 operator ++(Hex32 value) 90 | { 91 | for (int i = 0; i < 8; i++) 92 | { 93 | if (value._hex[i] < 15) 94 | { 95 | value._hex[i]++; 96 | break; 97 | } 98 | else value._hex[i] = 0; 99 | } 100 | 101 | return value; 102 | } 103 | 104 | public static Hex32 operator --(Hex32 value) 105 | { 106 | for (int i = 0; i < 8; i++) 107 | { 108 | if (value._hex[i] > 0) 109 | { 110 | value._hex[i]--; 111 | break; 112 | } 113 | else value._hex[i] = 15; 114 | } 115 | 116 | return value; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /QuanLib.Core/IBindable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface IBindable 10 | { 11 | public bool IsBound { get; } 12 | 13 | public void Bind(); 14 | 15 | public void Unbind(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.Core/IDataModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface IDataModel where TSelf : IDataModel 10 | { 11 | public static abstract TSelf CreateDefault(); 12 | 13 | public static abstract void Validate(TSelf model, string name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuanLib.Core/IDataModelOwner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface IDataModelOwner where TSelf : IDataModelOwner where TModel : IDataModel 10 | { 11 | public TModel ToDataModel(); 12 | 13 | public static abstract TSelf FromDataModel(TModel model); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuanLib.Core/ILogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface ILogger 10 | { 11 | public void Debug(string message); 12 | 13 | public void Debug(string message, Exception exception); 14 | 15 | public void Info(string message); 16 | 17 | public void Info(string message, Exception exception); 18 | 19 | public void Warn(string message); 20 | 21 | public void Warn(string message, Exception exception); 22 | 23 | public void Error(string message); 24 | 25 | public void Error(string message, Exception exception); 26 | 27 | public void Fatal(string message); 28 | 29 | public void Fatal(string message, Exception exception); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /QuanLib.Core/ILoggerGetter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface ILoggerGetter 10 | { 11 | public ILogger GetLogger(); 12 | 13 | public ILogger GetLogger(Type type); 14 | 15 | public ILogger GetLogger(string name); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.Core/IRunnable.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public interface IRunnable 11 | { 12 | public Thread? Thread { get; } 13 | 14 | public bool IsRunning { get; } 15 | 16 | public event EventHandler Started; 17 | 18 | public event EventHandler Stopped; 19 | 20 | public event EventHandler> ThrowException; 21 | 22 | public bool Start(); 23 | 24 | public void Stop(); 25 | 26 | public void WaitForStop(); 27 | 28 | public Task WaitForStopAsync(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /QuanLib.Core/ISingleton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public interface ISingleton where TSelf : ISingleton where TArgs : InstantiateArgs 10 | { 11 | public static abstract bool IsInstanceLoaded { get; } 12 | 13 | public static abstract TSelf Instance { get; } 14 | 15 | public static abstract TSelf LoadInstance(TArgs args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.Core/IndexRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public readonly struct IndexRange(int start, int end) 10 | { 11 | public readonly int Start = start; 12 | 13 | public readonly int End = end; 14 | 15 | public int Count => End - Start + 1; 16 | 17 | public bool IsWithinRange(int index) 18 | { 19 | return index >= Start && index <= End; 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return $"{Start}-{End}"; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuanLib.Core/InstantiateArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public class InstantiateArgs 10 | { 11 | public static readonly InstantiateArgs Empty = new(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuanLib.Core/Mapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public class Mapping where TKey : notnull where TValue : notnull 11 | { 12 | public Mapping() 13 | { 14 | _keyMap = []; 15 | _valueMap = []; 16 | } 17 | 18 | private readonly Dictionary _keyMap; 19 | 20 | private readonly Dictionary _valueMap; 21 | 22 | public IReadOnlyDictionary KeyMap => _keyMap; 23 | 24 | public IReadOnlyDictionary ValueMap => _valueMap; 25 | 26 | public TValue this[TKey key] 27 | { 28 | get => KeyMap[key]; 29 | set 30 | { 31 | _valueMap.Remove(_keyMap[key]); 32 | _valueMap.Add(value, key); 33 | _keyMap[key] = value; 34 | } 35 | } 36 | 37 | public TKey this[TValue value_] 38 | { 39 | get => ValueMap[value_]; 40 | set 41 | { 42 | _keyMap.Remove(_valueMap[value_]); 43 | _keyMap.Add(value, value_); 44 | _valueMap[value_] = value; 45 | } 46 | } 47 | 48 | public void AddKey(TKey key, TValue value) 49 | { 50 | _keyMap.Add(key, value); 51 | _valueMap.Add(value, key); 52 | } 53 | 54 | public void AddValue(TValue value, TKey key) 55 | { 56 | _valueMap.Add(value, key); 57 | _keyMap.Add(key, value); 58 | } 59 | 60 | public bool TryAddKey(TKey key, TValue value) 61 | { 62 | return _keyMap.TryAdd(key, value) && _valueMap.TryAdd(value, key); 63 | } 64 | 65 | public bool TryAddValue(TValue value, TKey key) 66 | { 67 | return _valueMap.TryAdd(value, key) && _keyMap.TryAdd(key, value); 68 | } 69 | 70 | public bool RemoveKey(TKey key) 71 | { 72 | return _valueMap.Remove(_keyMap[key]) && _keyMap.Remove(key); 73 | 74 | } 75 | 76 | public bool RemoveValue(TValue value) 77 | { 78 | return _keyMap.Remove(_valueMap[value]) && _valueMap.Remove(value); 79 | } 80 | 81 | public bool ContainsKey(TKey key) 82 | { 83 | return _keyMap.ContainsKey(key); 84 | } 85 | 86 | public bool ContainsValue(TValue value) 87 | { 88 | return _valueMap.ContainsKey(value); 89 | } 90 | 91 | public bool TryGetKey(TValue value, [MaybeNullWhen(false)] out TKey key) 92 | { 93 | return _valueMap.TryGetValue(value, out key); 94 | } 95 | 96 | public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) 97 | { 98 | return _keyMap.TryGetValue(key, out value); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /QuanLib.Core/MemberType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public enum MemberType 10 | { 11 | Class, 12 | 13 | Interface, 14 | 15 | Struct, 16 | 17 | Enum, 18 | 19 | Array, 20 | 21 | Delegate 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /QuanLib.Core/NetworkUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Sockets; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Core 10 | { 11 | public static class NetworkUtil 12 | { 13 | public static bool TestTcpConnectivity(IPAddress address, int port) 14 | { 15 | TcpClient client = new(); 16 | try 17 | { 18 | client.Connect(address, port); 19 | return true; 20 | } 21 | catch 22 | { 23 | return false; 24 | } 25 | finally 26 | { 27 | client.Dispose(); 28 | } 29 | } 30 | 31 | public static async Task TestTcpConnectivityAsync(IPAddress address, int port) 32 | { 33 | TcpClient client = new(); 34 | try 35 | { 36 | await client.ConnectAsync(address, port); 37 | return true; 38 | } 39 | catch 40 | { 41 | return false; 42 | } 43 | finally 44 | { 45 | client.Dispose(); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /QuanLib.Core/NullValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public static class NullValidator 11 | { 12 | public static bool TryValidateObject(object instance, out FieldInfo[] nullFields, out PropertyInfo[] nullProperties) 13 | { 14 | ArgumentNullException.ThrowIfNull(instance, nameof(instance)); 15 | 16 | Type type = instance.GetType(); 17 | FieldInfo[] fields = type.GetFields(BindingFlags.Instance); 18 | PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance); 19 | List nullFieldList = new(); 20 | List nullPropertyList = new(); 21 | 22 | foreach (FieldInfo field in fields) 23 | { 24 | if (field.GetCustomAttribute() is not null) 25 | continue; 26 | if (field.GetValue(instance) is null) 27 | nullFieldList.Add(field); 28 | } 29 | 30 | foreach (PropertyInfo property in properties) 31 | { 32 | if (property.GetCustomAttribute() is not null) 33 | continue; 34 | if (property.GetValue(instance) is null) 35 | nullPropertyList.Add(property); 36 | } 37 | 38 | nullFields = nullFieldList.ToArray(); 39 | nullProperties = nullPropertyList.ToArray(); 40 | return nullFields.Length == 0 && nullProperties.Length == 0; 41 | } 42 | 43 | public static void ValidateObject(object instance, string name) 44 | { 45 | ArgumentNullException.ThrowIfNull(instance, nameof(instance)); 46 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 47 | 48 | if (TryValidateObject(instance, out var nullFields, out var nullProperties)) 49 | return; 50 | 51 | StringBuilder message = new(); 52 | message.AppendLine("对象的一个或多个成员为null:"); 53 | foreach (var field in nullFields) 54 | message.AppendLine($"字段“{field.Name}”为null"); 55 | foreach (var property in nullProperties) 56 | message.AppendLine($"属性“{property.Name}”为null"); 57 | 58 | throw new ArgumentException(message.ToString().TrimEnd(), name); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /QuanLib.Core/NullableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] 10 | public class NullableAttribute : Attribute 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuanLib.Core/ObjectFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public static class ObjectFormatter 11 | { 12 | public static string Format(object? obj) 13 | { 14 | if (obj is null) 15 | return ""; 16 | 17 | if (obj is string text) 18 | return Format(text); 19 | 20 | if (obj is Type type) 21 | return Format(type); 22 | 23 | if (obj is Exception exception) 24 | return Format(exception); 25 | 26 | if (obj is IEnumerable enumerable) 27 | return Format(enumerable); 28 | 29 | return obj?.ToString() ?? Format((object?)null); 30 | } 31 | 32 | public static string Format(string? text) 33 | { 34 | if (text is null) 35 | return Format((object?)null); 36 | 37 | StringBuilder stringBuilder = new(text); 38 | stringBuilder.Replace("\\", "\\\\"); 39 | stringBuilder.Replace("\r\n", "\\r\\n"); 40 | stringBuilder.Replace("\r", "\\r"); 41 | stringBuilder.Replace("\n", "\\n"); 42 | stringBuilder.Replace("\t", "\\t"); 43 | stringBuilder.Replace("\v", "\\v"); 44 | stringBuilder.Replace("\f", "\\f"); 45 | stringBuilder.Replace("\'", "\\'"); 46 | stringBuilder.Replace("\"", "\\\""); 47 | stringBuilder.Insert(0, '\"'); 48 | stringBuilder.Append('\"'); 49 | 50 | return stringBuilder.ToString(); 51 | } 52 | 53 | public static string Format(Type? type) 54 | { 55 | if (type is null) 56 | return Format((object?)null); 57 | 58 | StringBuilder stringBuilder = new(); 59 | 60 | stringBuilder.Append(type.Namespace); 61 | stringBuilder.Append('.'); 62 | stringBuilder.Append(type.Name.TrimEnd('&').Replace("`" + type.GenericTypeArguments.Length, string.Empty)); 63 | 64 | if (type.GenericTypeArguments.Length > 0) 65 | { 66 | stringBuilder.Append('<'); 67 | stringBuilder.AppendJoin(',', type.GenericTypeArguments.Select(Format)); 68 | stringBuilder.Append('>'); 69 | } 70 | 71 | return stringBuilder.ToString(); 72 | } 73 | 74 | public static string Format(Exception? exception) 75 | { 76 | if (exception is null) 77 | return Format((object?)null); 78 | 79 | string s = $"{Format(exception.GetType())}: {Format(exception.Message)}"; 80 | if (exception.InnerException is not null) 81 | s += $" (InnerException: {Format(exception.InnerException)})"; 82 | return s; 83 | } 84 | 85 | public static string Format(IEnumerable? enumerable) 86 | { 87 | if (enumerable is null) 88 | return Format((object?)null); 89 | 90 | return $"[{string.Join(", ", enumerable.Select(s => Format(s)))}]"; 91 | } 92 | 93 | public static string Format(IEnumerable? enumerable) 94 | { 95 | if (enumerable is null) 96 | return Format((object?)null); 97 | 98 | List list = []; 99 | foreach (var item in enumerable) 100 | list.Add(Format(item)); 101 | return $"[{string.Join(", ", list)}]"; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /QuanLib.Core/ParseHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public delegate T ParseHandler(string s, IFormatProvider? provider); 10 | } 11 | -------------------------------------------------------------------------------- /QuanLib.Core/Parser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Core 10 | { 11 | public class Parser 12 | { 13 | public Parser(ParseHandler parseHandler) 14 | { 15 | ArgumentNullException.ThrowIfNull(parseHandler, nameof(parseHandler)); 16 | 17 | _parseHandler = parseHandler; 18 | _tryParseHandler = ([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out T result) => 19 | { 20 | if (s is null) 21 | { 22 | result = default; 23 | return false; 24 | } 25 | 26 | try 27 | { 28 | result = _parseHandler.Invoke(s, provider); 29 | return true; 30 | } 31 | catch 32 | { 33 | result = default; 34 | return false; 35 | } 36 | }; 37 | } 38 | 39 | public Parser(ParseHandler parseHandler, TryParseHandler tryParseHandler) 40 | { 41 | ArgumentNullException.ThrowIfNull(parseHandler, nameof(parseHandler)); 42 | ArgumentNullException.ThrowIfNull(tryParseHandler, nameof(tryParseHandler)); 43 | 44 | _parseHandler = parseHandler; 45 | _tryParseHandler = tryParseHandler; 46 | } 47 | 48 | private readonly ParseHandler _parseHandler; 49 | 50 | private readonly TryParseHandler _tryParseHandler; 51 | 52 | public T Parse(string s, IFormatProvider? provider) 53 | { 54 | try 55 | { 56 | return _parseHandler.Invoke(s, provider); 57 | } 58 | catch (TargetInvocationException targetInvocationException) when (targetInvocationException.InnerException is not null) 59 | { 60 | throw targetInvocationException.InnerException; 61 | } 62 | } 63 | 64 | public bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out T result) 65 | { 66 | return _tryParseHandler.Invoke(s, provider, out result); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /QuanLib.Core/ParserBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Core 10 | { 11 | public static class ParserBuilder 12 | { 13 | public static Parser FromType(Type type) 14 | { 15 | ArgumentNullException.ThrowIfNull(type, nameof(type)); 16 | 17 | if (type == typeof(string)) 18 | return new(StringParseHandler, StringTryParseHandler); 19 | 20 | if (!IsImplIParsable(type)) 21 | throw new InvalidOperationException($"类型“{type}”未实现 IParsable 接口"); 22 | 23 | Type iParsableType = GetIParsableType(type); 24 | InterfaceMapping interfaceMapping = type.GetInterfaceMap(iParsableType); 25 | 26 | MethodInfo? parseMethod = 27 | interfaceMapping.TargetMethods.Where(s => s.Name == "Parse").FirstOrDefault() ?? 28 | interfaceMapping.TargetMethods.Where(s => s.Name == $"System.IParsable<{type.Namespace}.{type.Name}>.Parse").FirstOrDefault() ?? 29 | throw new InvalidOperationException($"在类型“{type}”中找不到 Parse 方法"); 30 | 31 | MethodInfo? tryParseMethod = 32 | interfaceMapping.TargetMethods.Where(s => s.Name == "TryParse").FirstOrDefault() ?? 33 | interfaceMapping.TargetMethods.Where(s => s.Name == $"System.IParsable<{type.Namespace}.{type.Name}>.TryParse").FirstOrDefault() ?? 34 | throw new InvalidOperationException($"在类型“{type}”中找不到 TryParse 方法"); 35 | 36 | object parseHandler(string s, IFormatProvider? provider) 37 | { 38 | return parseMethod.Invoke(null, [s, provider]) ?? throw new FormatException(); 39 | } 40 | 41 | bool tryParseHandler([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out object result) 42 | { 43 | object?[] parameters = [s, null, null]; 44 | object? returnValue = tryParseMethod.Invoke(null, parameters); 45 | result = parameters[2]; 46 | if (returnValue is bool b) 47 | return b; 48 | else 49 | return false; 50 | } 51 | 52 | return new(parseHandler, tryParseHandler); 53 | } 54 | 55 | public static Parser FromType() where T : IParsable 56 | { 57 | return new(T.Parse, T.TryParse); 58 | } 59 | 60 | public static bool IsImplIParsable(Type type) 61 | { 62 | ArgumentNullException.ThrowIfNull(type, nameof(type)); 63 | 64 | return type.GetInterfaces().Any(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(IParsable<>)); 65 | } 66 | 67 | public static Type GetIParsableType(Type type) 68 | { 69 | ArgumentNullException.ThrowIfNull(type, nameof(type)); 70 | 71 | return typeof(IParsable<>).MakeGenericType(type); 72 | } 73 | 74 | private static string StringParseHandler(string s, IFormatProvider? provider) 75 | { 76 | ArgumentNullException.ThrowIfNull(s, nameof(s)); 77 | 78 | return s; 79 | } 80 | 81 | private static bool StringTryParseHandler([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out object result) 82 | { 83 | if (s is null) 84 | { 85 | result = null; 86 | return false; 87 | } 88 | 89 | result = s; 90 | return true; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /QuanLib.Core/PathType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public enum PathType 10 | { 11 | Unknown, 12 | 13 | Drive, 14 | 15 | Directory, 16 | 17 | File 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.Core/Platforms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | [Flags] 10 | public enum Platforms 11 | { 12 | None = 0, 13 | 14 | Windows = 1, 15 | 16 | Linux = 2, 17 | 18 | MacOS = 4 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /QuanLib.Core/ProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public struct ProgressBar 10 | { 11 | public ProgressBar(int total) 12 | { 13 | ThrowHelper.ArgumentOutOfMin(0, total, nameof(total)); 14 | 15 | Total = total; 16 | Current = 0; 17 | Length = 10; 18 | ProgressCharacter = '■'; 19 | BackgroundCharacter = '□'; 20 | } 21 | 22 | public int Total { get; } 23 | 24 | public int Current { get; set; } 25 | 26 | public int Length { get; set; } 27 | 28 | public char ProgressCharacter { get; set; } 29 | 30 | public char BackgroundCharacter { get; set; } 31 | 32 | public override readonly string ToString() 33 | { 34 | if (Length <= 0) 35 | return string.Empty; 36 | 37 | if (Total == 0 || Current > Total) 38 | return new string(ProgressCharacter, Length); 39 | 40 | double progress = (double)Current / Total; 41 | int leftCount = (int)Math.Round(Length * progress); 42 | int rightCount = Length - leftCount; 43 | StringBuilder stringBuilder = new(); 44 | stringBuilder.Append(ProgressCharacter, leftCount); 45 | stringBuilder.Append(BackgroundCharacter, rightCount); 46 | 47 | return stringBuilder.ToString(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /QuanLib.Core/Proportion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public readonly struct Proportion(int child, int parent) 10 | { 11 | public int Child { get; } = child; 12 | 13 | public int Parent { get; } = parent; 14 | 15 | public DivisionResult GetDivisionResult() 16 | { 17 | return DivisionResult.Compute(Child, Parent); 18 | } 19 | 20 | public double GetRatio() 21 | { 22 | return (double)Child / Parent; 23 | } 24 | 25 | public double GetRatio(int digits) 26 | { 27 | return Math.Round((double)Child / Parent, digits); 28 | } 29 | 30 | public double GetRatio(int digits, MidpointRounding mode) 31 | { 32 | return Math.Round((double)Child / Parent, digits, mode); 33 | } 34 | 35 | public double GetPercentage() 36 | { 37 | return (double)Child / Parent * 100; 38 | } 39 | 40 | public double GetPercentage(int digits) 41 | { 42 | return Math.Round((double)Child / Parent * 100, digits); 43 | } 44 | 45 | public double GetPercentage(int digits, MidpointRounding mode) 46 | { 47 | return Math.Round((double)Child / Parent * 100, digits, mode); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /QuanLib.Core/QuanLib.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /QuanLib.Core/QueueTimer.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public class QueueTimer 11 | { 12 | public QueueTimer(int maxCount) 13 | { 14 | ThrowHelper.ArgumentOutOfMin(1, maxCount, nameof(maxCount)); 15 | MaxCount = maxCount; 16 | TotalTime = TimeSpan.Zero; 17 | 18 | _queue = new(); 19 | 20 | TimeUpdated += OnTimeUpdated; 21 | } 22 | 23 | private readonly Queue _queue; 24 | 25 | public int MaxCount { get; } 26 | 27 | public TimeSpan TotalTime { get; private set; } 28 | 29 | public TimeSpan AverageTime 30 | { 31 | get 32 | { 33 | if (_queue.Count == 0) 34 | return TimeSpan.Zero; 35 | return TotalTime / _queue.Count; 36 | } 37 | } 38 | 39 | public event EventHandler> TimeUpdated; 40 | 41 | protected virtual void OnTimeUpdated(QueueTimer sender, EventArgs args) { } 42 | 43 | public void Update(TimeSpan time) 44 | { 45 | if (_queue.Count > MaxCount) 46 | TotalTime -= _queue.Dequeue(); 47 | 48 | TotalTime += time; 49 | _queue.Enqueue(time); 50 | TimeUpdated.Invoke(this, new(time)); 51 | } 52 | 53 | public TimeSpan[] ToArray() 54 | { 55 | return _queue.ToArray(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /QuanLib.Core/SerializationMemberInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public class SerializationMemberInfo 11 | { 12 | public SerializationMemberInfo(FieldInfo fieldInfo) 13 | { 14 | ArgumentNullException.ThrowIfNull(fieldInfo, nameof(fieldInfo)); 15 | 16 | _fieldInfo = fieldInfo; 17 | } 18 | 19 | public SerializationMemberInfo(PropertyInfo propertyInfo) 20 | { 21 | ArgumentNullException.ThrowIfNull(propertyInfo, nameof(propertyInfo)); 22 | 23 | _propertyInfo = propertyInfo; 24 | } 25 | 26 | private readonly FieldInfo? _fieldInfo; 27 | 28 | private readonly PropertyInfo? _propertyInfo; 29 | 30 | public bool IsFieldInfo => _fieldInfo is not null; 31 | 32 | public bool IsProperty => _propertyInfo is not null; 33 | 34 | public FieldInfo AsFieldInfo() => _fieldInfo ?? throw new InvalidOperationException(); 35 | 36 | public PropertyInfo AsPropertyInfo() => _propertyInfo ?? throw new InvalidOperationException(); 37 | 38 | public MemberInfo MemberInfo 39 | { 40 | get 41 | { 42 | if (_fieldInfo is not null) 43 | return _fieldInfo; 44 | else if (_propertyInfo is not null) 45 | return _propertyInfo; 46 | else 47 | throw new InvalidOperationException(); 48 | } 49 | } 50 | 51 | public Type MemberType 52 | { 53 | get 54 | { 55 | if (_fieldInfo is not null) 56 | return _fieldInfo.FieldType; 57 | else if (_propertyInfo is not null) 58 | return _propertyInfo.PropertyType; 59 | else 60 | throw new InvalidOperationException(); 61 | } 62 | } 63 | 64 | public string MemberName => MemberInfo.Name; 65 | 66 | public object? GetValue(object? obj) 67 | { 68 | if (_fieldInfo is not null) 69 | return _fieldInfo.GetValue(obj); 70 | else if (_propertyInfo is not null) 71 | return _propertyInfo.GetValue(obj); 72 | else 73 | throw new InvalidOperationException(); 74 | } 75 | 76 | public void SetValue(object? obj, object? value) 77 | { 78 | if (_fieldInfo is not null) 79 | _fieldInfo.SetValue(obj, value); 80 | else if (_propertyInfo is not null) 81 | _propertyInfo.SetValue(obj, value); 82 | else 83 | throw new InvalidOperationException(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /QuanLib.Core/Synchronized.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public class Synchronized 10 | { 11 | public Synchronized() 12 | { 13 | _semaphore = new(1); 14 | } 15 | 16 | private readonly SemaphoreSlim _semaphore; 17 | 18 | public void Invoke(Action action) 19 | { 20 | ArgumentNullException.ThrowIfNull(action, nameof(action)); 21 | 22 | _semaphore.Wait(); 23 | try 24 | { 25 | action.Invoke(); 26 | } 27 | catch 28 | { 29 | throw; 30 | } 31 | finally 32 | { 33 | _semaphore.Release(); 34 | } 35 | } 36 | 37 | public async Task InvokeAsync(Func func) 38 | { 39 | ArgumentNullException.ThrowIfNull(func, nameof(func)); 40 | 41 | await _semaphore.WaitAsync(); 42 | try 43 | { 44 | await func.Invoke(); 45 | } 46 | catch 47 | { 48 | throw; 49 | } 50 | finally 51 | { 52 | _semaphore.Release(); 53 | } 54 | } 55 | 56 | public async ValueTask InvokeAsync(Func func) 57 | { 58 | ArgumentNullException.ThrowIfNull(func, nameof(func)); 59 | 60 | await _semaphore.WaitAsync(); 61 | try 62 | { 63 | await func.Invoke(); 64 | } 65 | catch 66 | { 67 | throw; 68 | } 69 | finally 70 | { 71 | _semaphore.Release(); 72 | } 73 | } 74 | 75 | public T Invoke(Func func) 76 | { 77 | ArgumentNullException.ThrowIfNull(func, nameof(func)); 78 | 79 | _semaphore.Wait(); 80 | try 81 | { 82 | return func.Invoke(); 83 | } 84 | catch 85 | { 86 | throw; 87 | } 88 | finally 89 | { 90 | _semaphore.Release(); 91 | } 92 | } 93 | 94 | public async Task InvokeAsync(Func> func) 95 | { 96 | ArgumentNullException.ThrowIfNull(func, nameof(func)); 97 | 98 | await _semaphore.WaitAsync(); 99 | try 100 | { 101 | return await func.Invoke(); 102 | } 103 | catch 104 | { 105 | throw; 106 | } 107 | finally 108 | { 109 | _semaphore.Release(); 110 | } 111 | } 112 | 113 | public async ValueTask InvokeAsync(Func> func) 114 | { 115 | ArgumentNullException.ThrowIfNull(func, nameof(func)); 116 | 117 | await _semaphore.WaitAsync(); 118 | try 119 | { 120 | return await func.Invoke(); 121 | } 122 | catch 123 | { 124 | throw; 125 | } 126 | finally 127 | { 128 | _semaphore.Release(); 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /QuanLib.Core/ThreadOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public class ThreadOptions(string? name, bool isBackground, ThreadPriority priority) 10 | { 11 | public ThreadOptions() : this(null, false, ThreadPriority.Normal) { } 12 | 13 | public string? Name { get; set; } = name; 14 | 15 | public bool IsBackground { get; set; } = isBackground; 16 | 17 | public ThreadPriority Priority { get; set; } = priority; 18 | 19 | public ThreadOptions Clone() 20 | { 21 | return new(Name, IsBackground, Priority); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /QuanLib.Core/TimeUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | /// 10 | /// 时间单位 11 | /// 12 | public enum TimeUnit 13 | { 14 | Tikc, 15 | 16 | Microsecond, 17 | 18 | Millisecond, 19 | 20 | Second, 21 | 22 | Minute, 23 | 24 | Hour, 25 | 26 | Day, 27 | 28 | Month, 29 | 30 | Year, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /QuanLib.Core/TryParseHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public delegate bool TryParseHandler([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out T result); 11 | } 12 | -------------------------------------------------------------------------------- /QuanLib.Core/UnmanagedBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public abstract class UnmanagedBase : IDisposable 10 | { 11 | protected UnmanagedBase() 12 | { 13 | IsDisposed = false; 14 | } 15 | 16 | private readonly object _lock = new(); 17 | 18 | public bool IsDisposed { get; protected set; } 19 | 20 | protected abstract void DisposeUnmanaged(); 21 | 22 | protected virtual void NotDisposeUnmanaged() 23 | { 24 | 25 | } 26 | 27 | protected void Dispose(bool disposing) 28 | { 29 | lock (_lock) 30 | { 31 | if (IsDisposed) 32 | return; 33 | 34 | if (disposing) 35 | DisposeUnmanaged(); 36 | else 37 | NotDisposeUnmanaged(); 38 | 39 | IsDisposed = true; 40 | } 41 | } 42 | 43 | public void Dispose() 44 | { 45 | Dispose(disposing: true); 46 | GC.SuppressFinalize(this); 47 | } 48 | 49 | ~UnmanagedBase() 50 | { 51 | Dispose(disposing: false); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /QuanLib.Core/UnmanagedRunnable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public abstract class UnmanagedRunnable : RunnableBase, IDisposable 10 | { 11 | protected UnmanagedRunnable(ILoggerGetter? loggerGetter = null) : base(loggerGetter) 12 | { 13 | IsDisposed = false; 14 | } 15 | 16 | private readonly object _lock = new(); 17 | 18 | public bool IsDisposed { get; protected set; } 19 | 20 | public override bool Start() 21 | { 22 | if (IsDisposed) 23 | return false; 24 | 25 | return base.Start(); 26 | } 27 | 28 | public override void Stop() 29 | { 30 | Dispose(); 31 | base.Stop(); 32 | } 33 | 34 | protected abstract void DisposeUnmanaged(); 35 | 36 | protected virtual void NotDisposeUnmanaged() 37 | { 38 | 39 | } 40 | 41 | protected void Dispose(bool disposing) 42 | { 43 | lock (_lock) 44 | { 45 | if (IsDisposed) 46 | return; 47 | 48 | if (disposing) 49 | DisposeUnmanaged(); 50 | else 51 | NotDisposeUnmanaged(); 52 | 53 | IsDisposed = true; 54 | } 55 | } 56 | 57 | public void Dispose() 58 | { 59 | Dispose(disposing: true); 60 | GC.SuppressFinalize(this); 61 | } 62 | 63 | ~UnmanagedRunnable() 64 | { 65 | Dispose(disposing: false); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /QuanLib.Core/ValidationHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Core 9 | { 10 | public static class ValidationHelper 11 | { 12 | public static void Validate(object instance, string name) 13 | { 14 | ArgumentNullException.ThrowIfNull(instance, nameof(instance)); 15 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 16 | 17 | List results = []; 18 | if (!Validator.TryValidateObject(instance, new(instance), results, true)) 19 | { 20 | StringBuilder message = new(); 21 | message.AppendLine(); 22 | int count = 0; 23 | 24 | foreach (var result in results) 25 | { 26 | message.AppendLine(result.ErrorMessage); 27 | count++; 28 | } 29 | 30 | if (count > 0) 31 | { 32 | message.Insert(0, $"解析“{name}”时遇到{count}个错误:"); 33 | throw new ValidationException(message.ToString().TrimEnd()); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /QuanLib.Core/ValueRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Core 8 | { 9 | public readonly struct ValueRange where T : IComparable 10 | { 11 | public ValueRange(T min, T max) 12 | { 13 | ArgumentNullException.ThrowIfNull(min, nameof(min)); 14 | ArgumentNullException.ThrowIfNull(max, nameof(max)); 15 | ThrowHelper.ArgumentOutOfMin(min, max, nameof(max)); 16 | 17 | Min = min; 18 | Max = max; 19 | } 20 | 21 | public T Min { get; } 22 | 23 | public T Max { get; } 24 | 25 | public readonly bool IsWithinRange(T value) 26 | { 27 | ArgumentNullException.ThrowIfNull(value, nameof(value)); 28 | 29 | return value.CompareTo(Min) >= 0 && value.CompareTo(Max) <= 0; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/AllowedValuesIfAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.ComponentModel.DataAnnotations; 7 | using System.Globalization; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace QuanLib.DataAnnotations 13 | { 14 | public class AllowedValuesIfAttribute : ConditionalValidationAttribute 15 | { 16 | public AllowedValuesIfAttribute(string otherProperty, CompareOperator compareOperator, object? rightValue, params object?[] values) : base(otherProperty, compareOperator, rightValue, ErrorMessageHelper.AllowedValuesIfAttribute) 17 | { 18 | ArgumentNullException.ThrowIfNull(values, nameof(values)); 19 | 20 | Values = values.AsReadOnly(); 21 | } 22 | 23 | public ReadOnlyCollection Values { get; } 24 | 25 | public override string FormatErrorMessage(string name) 26 | { 27 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, OtherPropertyDisplayName ?? OtherProperty, CompareOperator.ToSymbol(), RightValue, ObjectFormatter.Format(Values)); 28 | } 29 | 30 | protected override ValidationResult? IsValidWhenTrue(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext) 31 | { 32 | if (Values.Contains(value)) 33 | return null; 34 | 35 | string[]? memberNames = validationContext.MemberName is not null ? [validationContext.MemberName] : null; 36 | return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), memberNames); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/CompareValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.DataAnnotations 11 | { 12 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 13 | public abstract class CompareValidationAttribute : PropertyValidationAttribute 14 | { 15 | public CompareValidationAttribute(string otherProperty, string errorMessage) : base(otherProperty, errorMessage) { } 16 | 17 | public override string FormatErrorMessage(string name) 18 | { 19 | ArgumentNullException.ThrowIfNull(name, nameof(name)); 20 | 21 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, OtherPropertyDisplayName ?? OtherProperty); 22 | } 23 | 24 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext) 25 | { 26 | if (!Compare(value, otherPropertyContext.Value)) 27 | { 28 | string[]? memberNames = validationContext.MemberName is not null ? [validationContext.MemberName] : null; 29 | return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), memberNames); 30 | } 31 | 32 | return null; 33 | } 34 | 35 | protected abstract bool Compare(object? value, object? other); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/ConditionalValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.DataAnnotations 10 | { 11 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)] 12 | public abstract class ConditionalValidationAttribute : PropertyValidationAttribute 13 | { 14 | public ConditionalValidationAttribute(string otherProperty, CompareOperator compareOperator, object? rightValue, string errorMessage) : base(otherProperty, errorMessage) 15 | { 16 | CompareOperator = compareOperator; 17 | RightValue = rightValue; 18 | } 19 | 20 | public CompareOperator CompareOperator { get; } 21 | 22 | public object? RightValue { get; } 23 | 24 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext) 25 | { 26 | if (!CompareHelper.Compare(otherPropertyContext.Value, RightValue, CompareOperator)) 27 | return null; 28 | 29 | return IsValidWhenTrue(value, validationContext, otherPropertyContext); 30 | } 31 | 32 | protected abstract ValidationResult? IsValidWhenTrue(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/DeniedValuesIfAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.ComponentModel.DataAnnotations; 7 | using System.Globalization; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace QuanLib.DataAnnotations 13 | { 14 | public class DeniedValuesIfAttribute : ConditionalValidationAttribute 15 | { 16 | public DeniedValuesIfAttribute(string otherProperty, CompareOperator compareOperator, object? rightValue, params object?[] values) : base(otherProperty, compareOperator, rightValue, ErrorMessageHelper.DeniedValuesIfAttribute) 17 | { 18 | ArgumentNullException.ThrowIfNull(values, nameof(values)); 19 | 20 | Values = values.AsReadOnly(); 21 | } 22 | 23 | public ReadOnlyCollection Values { get; } 24 | 25 | public override string FormatErrorMessage(string name) 26 | { 27 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, OtherPropertyDisplayName ?? OtherProperty, CompareOperator.ToSymbol(), RightValue, ObjectFormatter.Format(Values)); 28 | } 29 | 30 | protected override ValidationResult? IsValidWhenTrue(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext) 31 | { 32 | if (!Values.Contains(value)) 33 | return null; 34 | 35 | string[]? memberNames = validationContext.MemberName is not null ? [validationContext.MemberName] : null; 36 | return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), memberNames); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/DirectoryExistsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.DataAnnotations 10 | { 11 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)] 12 | public class DirectoryExistsAttribute : ValidationAttribute 13 | { 14 | public DirectoryExistsAttribute() : base(ErrorMessageHelper.DirectoryExistsAttribute) { } 15 | 16 | public override bool IsValid(object? value) 17 | { 18 | if (value is string text && Directory.Exists(text)) 19 | return true; 20 | else 21 | return false; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/EqualsAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class EqualsAttribute : CompareValidationAttribute 11 | { 12 | public EqualsAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.EqualsAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareEqual(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/ErrorMessageHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.DataAnnotations 8 | { 9 | public static class ErrorMessageHelper 10 | { 11 | private const string Prefix = "属性“{0}”的值验证失败:"; 12 | 13 | public const string RequiredAttribute = Prefix + "不能为空"; 14 | 15 | public const string RequiredIfAttribute = Prefix + "当另一个属性“{1}”的值 {2} {3} 时,当前属性的值不能为空"; 16 | 17 | public const string RangeAttribute = Prefix + "范围应该为{1}到{2}"; 18 | 19 | public const string MinLengthAttribute = Prefix + "长度最小为{1}"; 20 | 21 | public const string MaxLengthAttribute = Prefix + "长度最大为{1}"; 22 | 23 | public const string LengthAttribute = Prefix + "长度范围应该为{1}到{2}"; 24 | 25 | public const string StringLengthAttribute = Prefix + "文本长度范围应该为{2}到{1}"; 26 | 27 | public const string AllowedValuesAttribute = Prefix + "无效的值"; 28 | 29 | public const string DeniedValuesAttribute = Prefix + "无效的值"; 30 | 31 | public const string NewAllowedValuesAttribute = Prefix + "值只能为:{1}"; 32 | 33 | public const string NewDeniedValuesAttribute = Prefix + "值不为:{1}"; 34 | 35 | public const string AllowedValuesIfAttribute = Prefix + "当另一个属性“{1}”的值 {2} {3} 时,当前属性的值只能为:{4}"; 36 | 37 | public const string DeniedValuesIfAttribute = Prefix + "当另一个属性“{1}”的值 {2} {3} 时,当前属性的值不能为:{4}"; 38 | 39 | public const string CompareAttribute = Prefix + "需要与另一个属性“{1}”的值匹配"; 40 | 41 | public const string EqualsAttribute = Prefix + "需要与另一个属性“{1}”的值相等"; 42 | 43 | public const string NotEqualsAttribute = Prefix + "不能与另一个属性“{1}”的值相等"; 44 | 45 | public const string LessThanAttribute = Prefix + "需要小于另一个属性“{1}”的值"; 46 | 47 | public const string LessThanOrEqualsAttribute = Prefix + "需要小于或等于另一个属性“{1}”的值"; 48 | 49 | public const string GreaterThanAttribute = Prefix + "需要大于另一个属性“{1}”的值"; 50 | 51 | public const string GreaterThanOrEqualsAttribute = Prefix + "需要大于或等于另一个属性“{1}”的值"; 52 | 53 | public const string UrlAttribute = Prefix + "URL格式不合法"; 54 | 55 | public const string EmailAddressAttribute = Prefix + "邮箱地址格式不合法"; 56 | 57 | public const string PhoneAttribute = Prefix + "电话号码格式不合法"; 58 | 59 | public const string CreditCardAttribute = Prefix + "信用卡号格式不合法"; 60 | 61 | public const string FileExistsAttribute = Prefix + "指定的路径文件不存在"; 62 | 63 | public const string DirectoryExistsAttribute = Prefix + "指定的路径目录不存在"; 64 | 65 | public const string FileExtensionsAttribute = Prefix + "文件扩展名只能为{1}"; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/FileExistsAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.DataAnnotations 10 | { 11 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)] 12 | public class FileExistsAttribute : ValidationAttribute 13 | { 14 | public FileExistsAttribute() : base(ErrorMessageHelper.FileExistsAttribute) { } 15 | 16 | public override bool IsValid(object? value) 17 | { 18 | if (value is string text && File.Exists(text)) 19 | return true; 20 | else 21 | return false; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/GreaterThanAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class GreaterThanAttribute : CompareValidationAttribute 11 | { 12 | public GreaterThanAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.GreaterThanAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareGreaterThan(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/GreaterThanOrEqualsAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class GreaterThanOrEqualsAttribute : CompareValidationAttribute 11 | { 12 | public GreaterThanOrEqualsAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.GreaterThanOrEqualsAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareGreaterThanOrEquals(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/LessThanAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class LessThanAttribute : CompareValidationAttribute 11 | { 12 | public LessThanAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.LessThanAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareLessThan(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/LessThanOrEqualsAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class LessThanOrEqualsAttribute : CompareValidationAttribute 11 | { 12 | public LessThanOrEqualsAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.LessThanOrEqualsAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareLessThanOrEquals(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/NewAllowedValuesAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Globalization; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace QuanLib.DataAnnotations 12 | { 13 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)] 14 | public class NewAllowedValuesAttribute : ValidationAttribute 15 | { 16 | public NewAllowedValuesAttribute(params object?[] values) : base(ErrorMessageHelper.NewAllowedValuesAttribute) 17 | { 18 | ArgumentNullException.ThrowIfNull(values, nameof(values)); 19 | 20 | Values = values.AsReadOnly(); 21 | } 22 | 23 | public ReadOnlyCollection Values { get; } 24 | 25 | public override string FormatErrorMessage(string name) 26 | { 27 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ObjectFormatter.Format(Values)); 28 | } 29 | 30 | public override bool IsValid(object? value) 31 | { 32 | return Values.Contains(value); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/NewDeniedValuesAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Collections.ObjectModel; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Globalization; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace QuanLib.DataAnnotations 12 | { 13 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)] 14 | public class NewDeniedValuesAttribute : ValidationAttribute 15 | { 16 | public NewDeniedValuesAttribute(params object?[] values) : base(ErrorMessageHelper.NewDeniedValuesAttribute) 17 | { 18 | ArgumentNullException.ThrowIfNull(values, nameof(values)); 19 | 20 | Values = values.AsReadOnly(); 21 | } 22 | 23 | public ReadOnlyCollection Values { get; } 24 | 25 | public override string FormatErrorMessage(string name) 26 | { 27 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, ObjectFormatter.Format(Values)); 28 | } 29 | 30 | public override bool IsValid(object? value) 31 | { 32 | return !Values.Contains(value); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/NotEqualsAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.DataAnnotations 9 | { 10 | public class NotEqualsAttribute : CompareValidationAttribute 11 | { 12 | public NotEqualsAttribute(string otherProperty) : base(otherProperty, ErrorMessageHelper.NotEqualsAttribute) { } 13 | 14 | protected override bool Compare(object? value, object? other) 15 | { 16 | return CompareHelper.CompareNotEqual(value, other); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/PropertyContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.DataAnnotations 10 | { 11 | public class PropertyContext 12 | { 13 | public PropertyContext(ValidationContext validationContext, string propertyName) 14 | { 15 | PropertyInfo = validationContext.ObjectType.GetRuntimeProperty(propertyName); 16 | Value = PropertyInfo?.GetValue(validationContext.ObjectInstance, null); 17 | 18 | DisplayAttribute? displayAttribute = PropertyInfo?.GetCustomAttribute(); 19 | if (displayAttribute is not null) 20 | DisplayName = displayAttribute.GetName(); 21 | else 22 | DisplayName = propertyName; 23 | } 24 | 25 | public PropertyInfo? PropertyInfo { get; } 26 | 27 | public object? Value { get; } 28 | 29 | public string? DisplayName { get; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/PropertyValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.DataAnnotations 10 | { 11 | [AttributeUsage(AttributeTargets.Property)] 12 | public abstract class PropertyValidationAttribute : ValidationAttribute 13 | { 14 | public PropertyValidationAttribute(string otherProperty, string errorMessage) : base(errorMessage) 15 | { 16 | ArgumentNullException.ThrowIfNull(otherProperty); 17 | 18 | OtherProperty = otherProperty; 19 | } 20 | 21 | public string OtherProperty { get; } 22 | 23 | public string? OtherPropertyDisplayName { get; private set; } 24 | 25 | public override bool RequiresValidationContext => true; 26 | 27 | protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) 28 | { 29 | PropertyContext propertyContext = new(validationContext, OtherProperty); 30 | OtherPropertyDisplayName = propertyContext.DisplayName; 31 | return IsValid(value, validationContext, propertyContext); 32 | } 33 | 34 | protected abstract ValidationResult? IsValid(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/QuanLib.DataAnnotations.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /QuanLib.DataAnnotations/RequiredIfAttribute.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace QuanLib.DataAnnotations 12 | { 13 | public class RequiredIfAttribute : ConditionalValidationAttribute 14 | { 15 | public RequiredIfAttribute(string otherProperty, CompareOperator compareOperator, object? rightValue) : base(otherProperty, compareOperator, rightValue, ErrorMessageHelper.RequiredIfAttribute) 16 | { 17 | AllowEmptyStrings = false; 18 | } 19 | 20 | public bool AllowEmptyStrings { get; set; } 21 | 22 | public override string FormatErrorMessage(string name) 23 | { 24 | return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, OtherPropertyDisplayName ?? OtherProperty, CompareOperator.ToSymbol(), RightValue); 25 | } 26 | 27 | protected override ValidationResult? IsValidWhenTrue(object? value, ValidationContext validationContext, PropertyContext otherPropertyContext) 28 | { 29 | if (AllowEmptyStrings || value is not string stringValue) 30 | { 31 | if (value is not null) 32 | return null; 33 | } 34 | else 35 | { 36 | if (!string.IsNullOrWhiteSpace(stringValue)) 37 | return null; 38 | } 39 | 40 | string[]? memberNames = validationContext.MemberName is not null ? [validationContext.MemberName] : null; 41 | return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), memberNames); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /QuanLib.Downloader/DownloadTask.cs: -------------------------------------------------------------------------------- 1 | using Downloader; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Downloader 9 | { 10 | public class DownloadTask : IDisposable 11 | { 12 | public DownloadTask(string url, string? path = null, DownloadConfiguration? configuration = null) 13 | { 14 | ArgumentException.ThrowIfNullOrEmpty(url, nameof(url)); 15 | 16 | Url = url; 17 | Path = path; 18 | Configuration = configuration; 19 | 20 | var builder = GetBuilder(); 21 | Download = builder.Build(); 22 | Download.DownloadProgressChanged += Download_DownloadProgressChanged; 23 | _buffer = new(); 24 | } 25 | 26 | private MemoryStream _buffer; 27 | 28 | public string Url { get; } 29 | 30 | public string? Path { get; } 31 | 32 | public DownloadConfiguration? Configuration { get; } 33 | 34 | public IDownload Download { get; private set; } 35 | 36 | public Task Task => _Task ?? throw new InvalidOperationException("下载任务未开始"); 37 | private Task? _Task; 38 | 39 | public DownloadProgressChangedEventArgs DownloadProgressChangedEventArgs => _DownloadProgressChangedEventArgs ?? throw new InvalidOperationException("下载任务未开始"); 40 | private DownloadProgressChangedEventArgs? _DownloadProgressChangedEventArgs; 41 | 42 | public bool DownloadProgressAvailable => _DownloadProgressChangedEventArgs is not null; 43 | 44 | private void Download_DownloadProgressChanged(object? sender, DownloadProgressChangedEventArgs e) 45 | { 46 | _DownloadProgressChangedEventArgs = e; 47 | _buffer.Write(e.ReceivedBytes); 48 | } 49 | 50 | public async Task StartAsync() 51 | { 52 | if (Download.Status == DownloadStatus.None) 53 | { 54 | _Task = DownloadAsync(); 55 | return await _Task; 56 | } 57 | 58 | throw new InvalidOperationException("尝试重复启动下载任务"); 59 | } 60 | 61 | public void RetryIfFailed() 62 | { 63 | if (Download.Status == DownloadStatus.Failed) 64 | { 65 | Download.Dispose(); 66 | _buffer.Dispose(); 67 | 68 | var builder = GetBuilder(); 69 | Download = builder.Build(); 70 | Download.DownloadProgressChanged += Download_DownloadProgressChanged; 71 | _buffer = new(); 72 | _Task = DownloadAsync(); 73 | } 74 | } 75 | 76 | private DownloadBuilder GetBuilder() 77 | { 78 | DownloadBuilder builder = DownloadBuilder.New().WithUrl(Url); 79 | if (!string.IsNullOrEmpty(Path)) 80 | builder.WithFileLocation(Path); 81 | if (Configuration is not null) 82 | builder.WithConfiguration(Configuration); 83 | 84 | return builder; 85 | } 86 | 87 | private async Task DownloadAsync() 88 | { 89 | if (Path is not null && File.Exists(Path)) 90 | { 91 | try 92 | { 93 | File.Delete(Path); 94 | } 95 | catch 96 | { 97 | return null; 98 | } 99 | } 100 | 101 | Stream stream = await Download.StartAsync(); 102 | if (stream is null && _buffer.Length == Download.TotalFileSize) 103 | return _buffer; 104 | else 105 | return stream; 106 | } 107 | 108 | public void Dispose() 109 | { 110 | Download.Dispose(); 111 | GC.SuppressFinalize(this); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /QuanLib.Downloader/DownloaderExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Downloader 8 | { 9 | public class DownloaderExtension 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /QuanLib.Downloader/QuanLib.Downloader.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.Excel/ApplicationExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.Office.Interop.Excel; 8 | using ME = Microsoft.Office.Interop.Excel; 9 | 10 | namespace QuanLib.Excel 11 | { 12 | public static class ApplicationExtension 13 | { 14 | public static Workbook CreateWorkbook(this Application application, string path) 15 | { 16 | Workbook workbook = application.Workbooks.Add(Type.Missing); 17 | workbook.SaveAs(path); 18 | return workbook; 19 | } 20 | 21 | public static void SaveWorkbooks(this Application application) 22 | { 23 | foreach (Workbook book in application.Workbooks) 24 | book.Save(); 25 | } 26 | 27 | public static void CloseWorkbooks(this Application application) 28 | { 29 | foreach (Workbook book in application.Workbooks) 30 | book.Close(); 31 | } 32 | 33 | public static void CloseQuit(this Application application) 34 | { 35 | application.CloseWorkbooks(); 36 | application.Quit(); 37 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 38 | Marshal.ReleaseComObject(application); 39 | } 40 | 41 | public static void SaveCloseQuit(this Application application) 42 | { 43 | application.SaveWorkbooks(); 44 | application.CloseWorkbooks(); 45 | application.Quit(); 46 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 47 | Marshal.ReleaseComObject(application); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /QuanLib.Excel/ExcelUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Excel 8 | { 9 | public static class ExcelUtil 10 | { 11 | private static readonly char[] letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); 12 | 13 | public static string ToLetter(int value) 14 | { 15 | if (value <= 0) 16 | throw new ArgumentOutOfRangeException(nameof(value), value, "参数不能为等于或小于0"); 17 | 18 | List items = new(); 19 | StringBuilder sb = new(); 20 | while (true) 21 | { 22 | (int result, int remainder) result = Get(value); 23 | items.Add(result.remainder); 24 | if (result.result == 0) 25 | break; 26 | else value = result.result; 27 | } 28 | 29 | items.Reverse(); 30 | foreach (var item in items) 31 | sb.Append(letters[item - 1]); 32 | 33 | return sb.ToString(); 34 | 35 | static (int result, int remainder) Get(int value) 36 | { 37 | (int result, int remainder) result; 38 | result.result = value / 26; 39 | result.remainder = value % 26; 40 | if (result.remainder == 0 && result.result > 0) 41 | { 42 | result.remainder = 26; 43 | result.result--; 44 | } 45 | return result; 46 | } 47 | } 48 | 49 | public static string ToString(int row, int column) 50 | { 51 | return ToLetter(column) + row; 52 | } 53 | 54 | public static string ToString(int startRow, int startColumn, int endRow, int endColumn) 55 | { 56 | return ToString(startRow, startColumn) + ":" + ToString(endRow, endColumn); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /QuanLib.Excel/QuanLib.Excel.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | tlbimp 12 | 9 13 | 1 14 | 00020813-0000-0000-c000-000000000046 15 | 0 16 | false 17 | true 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /QuanLib.Excel/WorkbookExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.Office.Interop.Excel; 7 | using ME = Microsoft.Office.Interop.Excel; 8 | 9 | namespace QuanLib.Excel 10 | { 11 | public static class WorkbookExtension 12 | { 13 | public static Worksheet GetDefaultWorksheet(this Workbook workbook) => workbook.Worksheets[1]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuanLib.Excel/WorksheetExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.Office.Interop.Excel; 8 | using ME = Microsoft.Office.Interop.Excel; 9 | 10 | namespace QuanLib.Excel 11 | { 12 | public static class WorksheetExtension 13 | { 14 | public static int GetRowsCount(this Worksheet worksheet) => worksheet.Rows.Count; 15 | 16 | public static int GetColumnsCount(this Worksheet worksheet) => worksheet.Columns.Count; 17 | 18 | public static int GetUsedColumnsCount(this Worksheet worksheet) => worksheet.UsedRange.Columns.Count; 19 | 20 | public static int GetUsedRowsCount(this Worksheet worksheet) => worksheet.UsedRange.Rows.Count; 21 | 22 | public static ME.Range GetCell(this Worksheet worksheet, int row, int column) => (ME.Range)worksheet.Cells[row, column]; 23 | 24 | public static string? GetValue(this Worksheet worksheet, int row, int column) => worksheet.GetCell(row, column).GetValue(); 25 | 26 | public static bool TryGetValue(this Worksheet worksheet, int row, int column, [MaybeNullWhen(false)] out string value) 27 | => worksheet.GetCell(row, column).TryGetValue(out value); 28 | 29 | public static bool ContainsValue(this Worksheet worksheet, int row, int column) => worksheet.GetCell(row, column).ContainsValue(); 30 | 31 | public static void SetValue(this Worksheet worksheet, int row, int column, string value) => worksheet.GetCell(row, column).SetValue(value); 32 | 33 | public static Hyperlink GetHyperlink(this Worksheet worksheet, int row, int column) 34 | => worksheet.GetCell(row, column).GetHyperlink(); 35 | 36 | public static bool TryGetHyperlink(this Worksheet worksheet, int row, int column, [MaybeNullWhen(false)] out Hyperlink hyperlink) 37 | => worksheet.GetCell(row, column).TryGetHyperlink(out hyperlink); 38 | 39 | public static bool ContainsHyperlink(this Worksheet worksheet, int row, int column) => worksheet.GetCell(row, column).ContainsHyperlink(); 40 | 41 | public static void SetHyperlink(this Worksheet worksheet, int row, int column, string address, string? text = null, string? screenTip = null) 42 | => worksheet.GetCell(row, column).SetHyperlink(address, text, screenTip); 43 | 44 | public static ME.Range GetRange(this Worksheet worksheet, int startRow, int startColumn, int endRow, int endColumn) 45 | => worksheet.Range[ExcelUtil.ToString(startRow, startColumn, endRow, endColumn)]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /QuanLib.Game/Bounds.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public struct Bounds(Vector3 startPosition, Vector3 range) 10 | { 11 | public Vector3 StartPosition { get; set; } = startPosition; 12 | 13 | public Vector3 Range { get; set; } = range; 14 | 15 | public readonly Vector3 EndPosition => new(StartPosition.X + Range.X, StartPosition.Y + Range.Y, StartPosition.Z + Range.Z); 16 | 17 | public readonly bool Contains(T position) where T : IVector3 18 | { 19 | ArgumentNullException.ThrowIfNull(position, nameof(position)); 20 | 21 | Vector3 start = StartPosition; 22 | Vector3 end = EndPosition; 23 | return 24 | position.X >= start.X && 25 | position.Y >= start.Y && 26 | position.Z >= start.Z && 27 | position.X <= end.X && 28 | position.Y <= end.Y && 29 | position.Z <= end.Z; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /QuanLib.Game/CoordinateAxis.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public enum CoordinateAxis 10 | { 11 | X, 12 | Y, 13 | Z 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /QuanLib.Game/Direction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | /// 10 | /// 二维方向 11 | /// 12 | [Flags] 13 | public enum Direction 14 | { 15 | None = 0, 16 | 17 | Top = 1, 18 | 19 | Bottom = 2, 20 | 21 | Left = 4, 22 | 23 | Right = 8 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /QuanLib.Game/Facing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | /// 10 | /// 三维方向 11 | /// 12 | public enum Facing 13 | { 14 | Xp = 1, 15 | 16 | Xm = -1, 17 | 18 | Yp = 2, 19 | 20 | Ym = -2, 21 | 22 | Zp = 3, 23 | 24 | Zm = -3, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /QuanLib.Game/IPlane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public interface IPlane 10 | { 11 | public int Width { get; } 12 | 13 | public int Height { get; } 14 | 15 | public Facing NormalFacing { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.Game/IVector2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Numerics; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Game 9 | { 10 | public interface IVector2 where T : INumber, IConvertible 11 | { 12 | public T this[int index] { get; set; } 13 | 14 | public T X { get; set; } 15 | 16 | public T Y { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /QuanLib.Game/IVector3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Numerics; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Game 9 | { 10 | public interface IVector3 where T : INumber, IConvertible 11 | { 12 | public T this[int index] { get; set; } 13 | 14 | public T X { get; set; } 15 | 16 | public T Y { get; set; } 17 | 18 | public T Z { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /QuanLib.Game/Plane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public readonly struct Plane : IPlane 10 | { 11 | public Plane(int width, int height, Facing normalFacing) 12 | { 13 | Width = width; 14 | Height = height; 15 | NormalFacing = normalFacing; 16 | } 17 | 18 | public int Width { get; } 19 | 20 | public int Height { get; } 21 | 22 | public Facing NormalFacing { get; } 23 | 24 | public static bool TryParse(string s, out Plane result) 25 | { 26 | if (string.IsNullOrEmpty(s)) 27 | goto err; 28 | 29 | string[] items = s.Split(' '); 30 | if (items.Length != 3) 31 | goto err; 32 | 33 | if (int.TryParse(items[0], out var width) && 34 | int.TryParse(items[1], out var height) && 35 | Enum.TryParse(typeof(Facing), items[2], out var @enum) && 36 | @enum is Facing facing) 37 | { 38 | result = new(width, height, facing); 39 | return true; 40 | } 41 | 42 | err: 43 | result = default; 44 | return false; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /QuanLib.Game/PlaneAxis.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | /// 10 | /// 表示三维中的平面轴 11 | /// 12 | public enum PlaneAxis 13 | { 14 | XY, 15 | 16 | ZY, 17 | 18 | XZ 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /QuanLib.Game/QuanLib.Game.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /QuanLib.Game/Rotation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public struct Rotation 10 | { 11 | public Rotation(float yaw, float pitch) 12 | { 13 | _Yaw = Math.Clamp(yaw, -180f, 180f); 14 | _Pitch = Math.Clamp(pitch, -90f, 90f); 15 | } 16 | 17 | /// 18 | /// 偏转角 19 | /// 20 | public float Yaw 21 | { 22 | readonly get { return _Yaw; } 23 | set { _Yaw = Math.Clamp(value, -180f, 180f); } 24 | } 25 | private float _Yaw; 26 | 27 | /// 28 | /// 俯仰角 29 | /// 30 | public float Pitch 31 | { 32 | readonly get { return _Pitch; } 33 | set { _Pitch = Math.Clamp(value, -90f, 90f); } 34 | } 35 | private float _Pitch; 36 | 37 | public readonly Facing YawFacing 38 | { 39 | get 40 | { 41 | if (_Yaw < -135) 42 | return Facing.Zm; 43 | else if (_Yaw < -45) 44 | return Facing.Xp; 45 | else if (_Yaw < 45) 46 | return Facing.Zp; 47 | else if (_Yaw < 135) 48 | return Facing.Xm; 49 | else 50 | return Facing.Zm; 51 | } 52 | } 53 | 54 | public readonly Facing PitchFacing => _Pitch < 0 ? Facing.Yp : Facing.Ym; 55 | 56 | public readonly bool Contains(Facing facing) 57 | { 58 | return facing switch 59 | { 60 | Facing.Zp => _Yaw > -90 && _Yaw <= 90, 61 | Facing.Zm => _Yaw <= -90 || _Yaw > 90, 62 | Facing.Xp => _Yaw < 0, 63 | Facing.Xm => _Yaw >= 0, 64 | Facing.Yp => _Pitch < 0, 65 | Facing.Ym => _Pitch >= 0, 66 | _ => throw new InvalidOperationException(), 67 | }; 68 | } 69 | 70 | public readonly Vector3 ToDirection() 71 | { 72 | float yaw = _Yaw; 73 | float pitch = _Pitch; 74 | if (yaw < 0) 75 | yaw += 360; 76 | yaw = -yaw; 77 | pitch = -pitch; 78 | 79 | double radiansYaw = yaw * (MathF.PI / 180); 80 | double radiansPitch = pitch * (MathF.PI / 180); 81 | 82 | double dirX = Math.Cos(radiansPitch) * Math.Sin(radiansYaw); 83 | double dirY = Math.Sin(radiansPitch); 84 | double dirZ = Math.Cos(radiansPitch) * Math.Cos(radiansYaw); 85 | 86 | return new(dirX, dirY, dirZ); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /QuanLib.Game/Vector2Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.Game 8 | { 9 | public static class Vector2Util 10 | { 11 | public static Vector2 ToIntVector2(this Vector2 source) 12 | { 13 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 14 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 15 | return new(x, y); 16 | } 17 | 18 | public static Vector2 ToIntVector2(this Vector2 source) 19 | { 20 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 21 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 22 | return new(x, y); 23 | } 24 | 25 | public static Vector2 ToIntVector2(this Vector2 source) 26 | { 27 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 28 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 29 | return new(x, y); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /QuanLib.Game/Vector3Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Numerics; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.Game 9 | { 10 | public static class Vector3Util 11 | { 12 | public static Vector3 ToIntVector3(this Vector3 source) 13 | { 14 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 15 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 16 | int z = (int)Math.Round(source.Z, MidpointRounding.ToNegativeInfinity); 17 | return new(x, y, z); 18 | } 19 | 20 | public static Vector3 ToIntVector3(this Vector3 source) 21 | { 22 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 23 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 24 | int z = (int)Math.Round(source.Z, MidpointRounding.ToNegativeInfinity); 25 | return new(x, y, z); 26 | } 27 | 28 | public static Vector3 ToIntVector3(this Vector3 source) 29 | { 30 | int x = (int)Math.Round(source.X, MidpointRounding.ToNegativeInfinity); 31 | int y = (int)Math.Round(source.Y, MidpointRounding.ToNegativeInfinity); 32 | int z = (int)Math.Round(source.Z, MidpointRounding.ToNegativeInfinity); 33 | return new(x, y, z); 34 | } 35 | 36 | public static Vector3 Offset(this Vector3 position, Facing facing, T offset) where T : INumber, IConvertible 37 | { 38 | switch (facing) 39 | { 40 | case Facing.Xp: 41 | position.X += offset; 42 | break; 43 | case Facing.Xm: 44 | position.X -= offset; 45 | break; 46 | case Facing.Yp: 47 | position.Y += offset; 48 | break; 49 | case Facing.Ym: 50 | position.Y -= offset; 51 | break; 52 | case Facing.Zp: 53 | position.Z += offset; 54 | break; 55 | case Facing.Zm: 56 | position.Z -= offset; 57 | break; 58 | default: 59 | throw new InvalidOperationException(); 60 | } 61 | 62 | return position; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /QuanLib.IO/BytesWriteTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO 8 | { 9 | public class BytesWriteTask : WriteTask 10 | { 11 | public BytesWriteTask(string destinationPath, byte[] bytes) : base(destinationPath) 12 | { 13 | ArgumentNullException.ThrowIfNull(bytes, nameof(bytes)); 14 | 15 | _bytes = bytes; 16 | } 17 | 18 | private readonly byte[] _bytes; 19 | 20 | public override void Run() 21 | { 22 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 23 | File.WriteAllBytes(DestinationPath, _bytes); 24 | } 25 | 26 | public override async Task RunAsync(CancellationToken cancellationToken = default) 27 | { 28 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 29 | await File.WriteAllBytesAsync(DestinationPath, _bytes, cancellationToken); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /QuanLib.IO/CombineHelper.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.IO 9 | { 10 | public static class CombineHelper 11 | { 12 | public static string Combine(char separatorChar, string value1, string value2) 13 | { 14 | ArgumentException.ThrowIfNullOrEmpty(value1, nameof(value1)); 15 | ArgumentException.ThrowIfNullOrEmpty(value2, nameof(value2)); 16 | 17 | value1 = value1.TrimEnd(separatorChar); 18 | value2 = value2.TrimStart(separatorChar); 19 | return $"{value1}{separatorChar}{value2}"; 20 | } 21 | 22 | public static string Combine(char separatorChar, string value1, string value2, string value3) 23 | { 24 | ArgumentException.ThrowIfNullOrEmpty(value1, nameof(value1)); 25 | ArgumentException.ThrowIfNullOrEmpty(value2, nameof(value2)); 26 | ArgumentException.ThrowIfNullOrEmpty(value3, nameof(value3)); 27 | 28 | value1 = value1.TrimEnd(separatorChar); 29 | value2 = value2.Trim(separatorChar); 30 | value3 = value3.TrimStart(separatorChar); 31 | return $"{value1}{separatorChar}{value2}{separatorChar}{value3}"; 32 | } 33 | 34 | public static string Combine(char separatorChar, string value1, string value2, string value3, string value4) 35 | { 36 | ArgumentException.ThrowIfNullOrEmpty(value1, nameof(value1)); 37 | ArgumentException.ThrowIfNullOrEmpty(value2, nameof(value2)); 38 | ArgumentException.ThrowIfNullOrEmpty(value3, nameof(value3)); 39 | ArgumentException.ThrowIfNullOrEmpty(value4, nameof(value4)); 40 | 41 | value1 = value1.TrimEnd(separatorChar); 42 | value2 = value2.Trim(separatorChar); 43 | value3 = value3.Trim(separatorChar); 44 | value4 = value4.TrimStart(separatorChar); 45 | return $"{value1}{separatorChar}{value2}{separatorChar}{value3}{separatorChar}{value4}"; 46 | } 47 | 48 | public static string Combine(char separatorChar, params string[] values) 49 | { 50 | ArgumentNullException.ThrowIfNull(values, nameof(values)); 51 | CollectionValidator.ValidateNullOrEmpty(values, nameof(values)); 52 | 53 | if (values.Length == 0) 54 | return string.Empty; 55 | if (values.Length == 1) 56 | return values[0]; 57 | 58 | StringBuilder sb = new(); 59 | sb.Append(values[0].TrimEnd(separatorChar)); 60 | for (int i = 1; i < values.Length - 1; i++) 61 | { 62 | sb.Append(separatorChar); 63 | sb.Append(values[i].Trim(separatorChar)); 64 | } 65 | sb.Append(separatorChar); 66 | sb.Append(values[^1].TrimStart(separatorChar)); 67 | 68 | return sb.ToString(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /QuanLib.IO/DirectoryUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO 8 | { 9 | public class DirectoryUtil 10 | { 11 | public static void CreateDirectoryIfNotExists(string directoryPath) 12 | { 13 | ArgumentNullException.ThrowIfNull(directoryPath, nameof(directoryPath)); 14 | 15 | string fullPath = Path.GetFullPath(directoryPath); 16 | 17 | if (!Directory.Exists(fullPath)) 18 | Directory.CreateDirectory(fullPath); 19 | } 20 | 21 | public static string[] GetAllFiles(string path) 22 | { 23 | ArgumentException.ThrowIfNullOrEmpty(path, nameof(path)); 24 | 25 | List result = []; 26 | string[] directorys = Directory.GetDirectories(path); 27 | result.AddRange(Directory.GetFiles(path)); 28 | 29 | foreach (string directory in directorys) 30 | result.AddRange(GetAllFiles(directory)); 31 | 32 | return result.ToArray(); 33 | } 34 | 35 | public static string[] GetAllDirectories(string path) 36 | { 37 | ArgumentException.ThrowIfNullOrEmpty(path, nameof(path)); 38 | 39 | List result = []; 40 | string[] directories = Directory.GetDirectories(path); 41 | result.AddRange(directories); 42 | 43 | foreach (string directory in directories) 44 | result.AddRange(GetAllDirectories(directory)); 45 | 46 | return result.ToArray(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /QuanLib.IO/Extensions/PathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO.Extensions 8 | { 9 | public static class PathExtensions 10 | { 11 | public static string PathCombine(this string source, string path) 12 | { 13 | ArgumentNullException.ThrowIfNull(source, nameof(source)); 14 | 15 | return Path.Combine(source, path); 16 | } 17 | 18 | public static string PathCombine(this string source, string path1, string path2) 19 | { 20 | ArgumentNullException.ThrowIfNull(source, nameof(source)); 21 | 22 | return Path.Combine(source, path1, path2); 23 | } 24 | 25 | public static string PathCombine(this string source, string path1, string path2, string path3) 26 | { 27 | ArgumentNullException.ThrowIfNull(source, nameof(source)); 28 | 29 | return Path.Combine(source, path1, path2, path3); 30 | } 31 | 32 | public static FileInfo CreateFileInfo(this string source) 33 | { 34 | ArgumentNullException.ThrowIfNull(source, nameof(source)); 35 | 36 | return new(source); 37 | } 38 | 39 | public static DirectoryInfo CreateDirectoryInfo(this string source) 40 | { 41 | ArgumentNullException.ThrowIfNull(source, nameof(source)); 42 | 43 | return new(source); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /QuanLib.IO/FileSystem/ContainerNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO.FileSystem 10 | { 11 | public abstract class ContainerNode : Node, IReadOnlyDictionary 12 | { 13 | protected ContainerNode() 14 | { 15 | _items = []; 16 | } 17 | 18 | protected readonly Dictionary _items; 19 | 20 | public Node this[string key] => _items[key]; 21 | 22 | public IEnumerable Keys => _items.Keys; 23 | 24 | public IEnumerable Values => _items.Values; 25 | 26 | public int Count => _items.Count; 27 | 28 | public virtual void Add(Node value) 29 | { 30 | _items.Add(value.Name, value); 31 | value.ParentNode = this; 32 | } 33 | 34 | public virtual bool Remvoe(string key) 35 | { 36 | ArgumentException.ThrowIfNullOrEmpty(key, nameof(key)); 37 | 38 | if (_items.Remove(key, out var value)) 39 | { 40 | value.ParentNode = null; 41 | return true; 42 | } 43 | 44 | return false; 45 | } 46 | 47 | public DirectoryNode[] GetDirectoryNodes() 48 | { 49 | return _items.Values.OfType().ToArray(); 50 | } 51 | 52 | public FileNode[] GetFileNodes() 53 | { 54 | return _items.Values.OfType().ToArray(); 55 | } 56 | 57 | public DirectoryNode? GetAsDirectoryNode(string key) 58 | { 59 | return _items.TryGetValue(key, out var value) ? value as DirectoryNode : null; 60 | } 61 | 62 | public FileNode? GetAsFileNode(string key) 63 | { 64 | return _items.TryGetValue(key, out var value) ? value as FileNode : null; 65 | } 66 | 67 | public bool ContainsKey(string key) 68 | { 69 | return _items.ContainsKey(key); 70 | } 71 | 72 | public bool TryGetValue(string key, [MaybeNullWhen(false)] out Node value) 73 | { 74 | return _items.TryGetValue(key, out value); 75 | } 76 | 77 | public IEnumerator> GetEnumerator() 78 | { 79 | return _items.GetEnumerator(); 80 | } 81 | 82 | IEnumerator IEnumerable.GetEnumerator() 83 | { 84 | return ((IEnumerable)_items).GetEnumerator(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /QuanLib.IO/FileSystem/DirectoryNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO.FileSystem 10 | { 11 | public class DirectoryNode : ContainerNode 12 | { 13 | public DirectoryNode(string name) 14 | { 15 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 16 | 17 | Name = name; 18 | } 19 | 20 | public override string Name { get; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /QuanLib.IO/FileSystem/FIleNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO.FileSystem 8 | { 9 | public class FileNode : Node 10 | { 11 | public FileNode(string name) 12 | { 13 | ArgumentException.ThrowIfNullOrEmpty(name, nameof(name)); 14 | 15 | Name = name; 16 | } 17 | 18 | public override string Name { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /QuanLib.IO/FileSystem/Node.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO.FileSystem 8 | { 9 | public abstract class Node 10 | { 11 | public abstract string Name { get; } 12 | 13 | public virtual ContainerNode? ParentNode { get; internal set; } 14 | 15 | public virtual string GetFullName(char separatorChar) 16 | { 17 | if (ParentNode is not null) 18 | return ParentNode.GetFullName(separatorChar) + separatorChar + Name; 19 | else 20 | return Name; 21 | } 22 | 23 | public void Delete() 24 | { 25 | if (ParentNode is null) 26 | return; 27 | 28 | ParentNode.Remvoe(Name); 29 | ParentNode = null; 30 | } 31 | 32 | public DeviceNode? AsDeviceNode() 33 | { 34 | return this as DeviceNode; 35 | } 36 | 37 | public DirectoryNode? AsDirectoryNode() 38 | { 39 | return this as DirectoryNode; 40 | } 41 | 42 | public FileNode? AsFIleNode() 43 | { 44 | return this as FileNode; 45 | } 46 | 47 | public override string ToString() 48 | { 49 | return GetFullName('/'); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /QuanLib.IO/FileUtil.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO 10 | { 11 | public static class FileUtil 12 | { 13 | public static PathType GetPathType(string path) 14 | { 15 | ArgumentNullException.ThrowIfNull(path, nameof(path)); 16 | 17 | string fullPath = Path.GetFullPath(path); 18 | 19 | foreach (var drive in DriveInfo.GetDrives()) 20 | { 21 | if (fullPath == drive.Name) 22 | return PathType.Drive; 23 | } 24 | 25 | if (Directory.Exists(fullPath)) 26 | return PathType.Directory; 27 | else if (File.Exists(fullPath)) 28 | return PathType.File; 29 | 30 | return PathType.Unknown; 31 | } 32 | 33 | public static void CreateFileDirectoryIfNotExists(string filePath) 34 | { 35 | ArgumentNullException.ThrowIfNull(filePath, nameof(filePath)); 36 | 37 | string fullPath = Path.GetFullPath(filePath); 38 | string? directoryPath = Path.GetDirectoryName(fullPath); 39 | if (directoryPath is null) 40 | return; 41 | 42 | if (!Directory.Exists(directoryPath)) 43 | Directory.CreateDirectory(directoryPath); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /QuanLib.IO/FileWriteQueue.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO 10 | { 11 | public class FileWriteQueue : RunnableBase 12 | { 13 | public FileWriteQueue() 14 | { 15 | _queue = new(); 16 | _enqueue = new(false); 17 | } 18 | 19 | 20 | private readonly ConcurrentQueue _queue; 21 | 22 | private readonly AutoResetEvent _enqueue; 23 | 24 | public void Submit(WriteTask writeTask) 25 | { 26 | ArgumentNullException.ThrowIfNull(writeTask, nameof(writeTask)); 27 | 28 | _queue.Enqueue(writeTask); 29 | _enqueue.Set(); 30 | } 31 | 32 | protected override void Run() 33 | { 34 | while (IsRunning) 35 | { 36 | while (_queue.TryDequeue(out var task)) 37 | task.Run(); 38 | 39 | _enqueue.WaitOne(10); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /QuanLib.IO/HashUtil.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Security.Cryptography; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.IO 11 | { 12 | /// 13 | /// 哈希工具类 14 | /// 15 | public static class HashUtil 16 | { 17 | private static HashAlgorithm Create(HashType hashType) 18 | { 19 | return hashType switch 20 | { 21 | HashType.SHA1 => SHA1.Create(), 22 | HashType.SHA256 => SHA256.Create(), 23 | HashType.SHA384 => SHA384.Create(), 24 | HashType.SHA512 => SHA512.Create(), 25 | HashType.MD5 => MD5.Create(), 26 | _ => throw new InvalidOperationException(), 27 | }; 28 | } 29 | 30 | public static byte[] GetHashValue(byte[] bytes, HashType hashType) 31 | { 32 | ArgumentNullException.ThrowIfNull(bytes, nameof(bytes)); 33 | 34 | using HashAlgorithm hashAlgorithm = Create(hashType); 35 | return hashAlgorithm.ComputeHash(bytes); 36 | } 37 | 38 | public static byte[] GetHashValue(Stream stream, HashType hashType) 39 | { 40 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 41 | 42 | using HashAlgorithm hashAlgorithm = Create(hashType); 43 | return hashAlgorithm.ComputeHash(stream); 44 | } 45 | 46 | public static byte[] GetHashValue(string path, HashType hashType) 47 | { 48 | ArgumentException.ThrowIfNullOrEmpty(path, nameof(path)); 49 | 50 | using FileStream fileStream = new(path, FileMode.Open); 51 | byte[] result = GetHashValue(fileStream, hashType); 52 | fileStream.Close(); 53 | return result; 54 | } 55 | 56 | public static string GetHashString(byte[] bytes, HashType hashType) 57 | { 58 | byte[] hash = GetHashValue(bytes, hashType); 59 | return BytesToHexString(hash); 60 | } 61 | 62 | public static string GetHashString(Stream stream, HashType hashType) 63 | { 64 | byte[] hash = GetHashValue(stream, hashType); 65 | return BytesToHexString(hash); 66 | } 67 | 68 | public static string GetHashString(string path, HashType hashType) 69 | { 70 | byte[] hash = GetHashValue(path, hashType); 71 | return BytesToHexString(hash); 72 | } 73 | 74 | public static bool Equals(Stream stream1, Stream stream2, HashType hashType) 75 | { 76 | return GetHashValue(stream1, hashType).SequenceEqual(GetHashValue(stream2, hashType)); 77 | } 78 | 79 | public static bool Equals(string path1, string path2, HashType hashType) 80 | { 81 | return GetHashValue(path1, hashType).SequenceEqual(GetHashValue(path2, hashType)); 82 | } 83 | 84 | private static string BytesToHexString(byte[] bytes) 85 | { 86 | ArgumentNullException.ThrowIfNull(bytes, nameof(bytes)); 87 | 88 | StringBuilder result = new(); 89 | for (int i = 0; i < bytes.Length; i++) 90 | result.Append(bytes[i].ToString("x2")); 91 | return result.ToString(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /QuanLib.IO/ITextListener.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using QuanLib.Core.Events; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO 10 | { 11 | public interface ITextListener 12 | { 13 | public Encoding Encoding { get; } 14 | 15 | public event EventHandler> WriteText; 16 | 17 | public event EventHandler> WriteLineText; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /QuanLib.IO/LinesWriteTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO 8 | { 9 | public class LinesWriteTask : WriteTask 10 | { 11 | public LinesWriteTask(string destinationPath, IEnumerable lines, Encoding encoding) : base(destinationPath) 12 | { 13 | ArgumentNullException.ThrowIfNull(lines, nameof(lines)); 14 | ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); 15 | 16 | _lines = lines; 17 | Encoding = encoding; 18 | } 19 | 20 | public LinesWriteTask(string destinationPath, IEnumerable lines) : this(destinationPath, lines, Encoding.UTF8) { } 21 | 22 | private readonly IEnumerable _lines; 23 | 24 | private Encoding Encoding { get; } 25 | 26 | public override void Run() 27 | { 28 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 29 | File.WriteAllLines(DestinationPath, _lines, Encoding); 30 | } 31 | 32 | public override async Task RunAsync(CancellationToken cancellationToken = default) 33 | { 34 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 35 | await File.WriteAllLinesAsync(DestinationPath, _lines, Encoding, cancellationToken); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /QuanLib.IO/PollingTextFileListener.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using QuanLib.Core.Events; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO 10 | { 11 | public class PollingTextFileListener : PollingFileListener, ITextListener 12 | { 13 | public PollingTextFileListener(string path, Encoding encoding, ILoggerGetter? loggerGetter = null) : base(path, loggerGetter) 14 | { 15 | ArgumentNullException.ThrowIfNull(path, nameof(path)); 16 | ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); 17 | 18 | Encoding = encoding; 19 | _temp = new(); 20 | 21 | WriteText += OnWriteText; 22 | WriteLineText += OnWriteLineText; 23 | } 24 | 25 | private readonly StringBuilder _temp; 26 | 27 | public Encoding Encoding { get; } 28 | 29 | public event EventHandler> WriteText; 30 | 31 | public event EventHandler> WriteLineText; 32 | 33 | protected override void OnWriteBytes(PollingFileListener sender, EventArgs e) 34 | { 35 | base.OnWriteBytes(sender, e); 36 | 37 | WriteText.Invoke(this, new(Encoding.GetString(e.Argument))); 38 | } 39 | 40 | protected virtual void OnWriteText(ITextListener sender, EventArgs e) 41 | { 42 | string[] lines = e.Argument.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); 43 | _temp.Append(lines[0]); 44 | if (lines.Length > 1) 45 | { 46 | if (_temp.Length > 0) 47 | { 48 | lines[0] = _temp.ToString(); 49 | _temp.Clear(); 50 | _temp.Append(lines[^1]); 51 | } 52 | for (int i = 0; i < lines.Length - 1; i++) 53 | { 54 | WriteLineText.Invoke(this, new(lines[i])); 55 | } 56 | } 57 | } 58 | 59 | protected virtual void OnWriteLineText(ITextListener sender, EventArgs e) { } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /QuanLib.IO/QuanLib.IO.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /QuanLib.IO/StreamWriteQueue.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.IO 10 | { 11 | public class StreamWriteQueue : RunnableBase 12 | { 13 | public StreamWriteQueue(Stream stream, ILoggerGetter? loggerGetter = null) : base(loggerGetter) 14 | { 15 | ArgumentNullException.ThrowIfNull(stream, nameof(stream)); 16 | 17 | BaseStream = stream; 18 | _queue = new(); 19 | _enqueue = new(false); 20 | } 21 | 22 | private readonly ConcurrentQueue _queue; 23 | 24 | private readonly AutoResetEvent _enqueue; 25 | 26 | public Stream BaseStream { get; } 27 | 28 | public void Submit(byte[] bytes) 29 | { 30 | ArgumentNullException.ThrowIfNull(bytes, nameof(bytes)); 31 | 32 | _queue.Enqueue(bytes); 33 | _enqueue.Set(); 34 | } 35 | 36 | protected override void Run() 37 | { 38 | while (IsRunning) 39 | { 40 | while (_queue.TryDequeue(out var bytes)) 41 | BaseStream.Write(bytes); 42 | 43 | _enqueue.WaitOne(10); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /QuanLib.IO/TextWriteTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO 8 | { 9 | public class TextWriteTask : WriteTask 10 | { 11 | public TextWriteTask(string destinationPath, string text, Encoding encoding) : base(destinationPath) 12 | { 13 | ArgumentNullException.ThrowIfNull(text, nameof(text)); 14 | ArgumentNullException.ThrowIfNull(encoding, nameof(encoding)); 15 | 16 | _text = text; 17 | Encoding = encoding; 18 | } 19 | 20 | public TextWriteTask(string destinationPath, string text) : this(destinationPath, text, Encoding.UTF8) { } 21 | 22 | private readonly string _text; 23 | 24 | private Encoding Encoding { get; } 25 | 26 | public override void Run() 27 | { 28 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 29 | File.WriteAllText(DestinationPath, _text, Encoding); 30 | } 31 | 32 | public override async Task RunAsync(CancellationToken cancellationToken = default) 33 | { 34 | FileUtil.CreateFileDirectoryIfNotExists(DestinationPath); 35 | await File.WriteAllTextAsync(DestinationPath, _text, Encoding, cancellationToken); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /QuanLib.IO/WriteTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.IO 8 | { 9 | public abstract class WriteTask 10 | { 11 | protected WriteTask(string destinationPath) 12 | { 13 | ArgumentException.ThrowIfNullOrEmpty(destinationPath, nameof(destinationPath)); 14 | 15 | DestinationPath = destinationPath; 16 | } 17 | 18 | public string DestinationPath { get; } 19 | 20 | public abstract void Run(); 21 | 22 | public abstract Task RunAsync(CancellationToken cancellationToken = default); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /QuanLib.IO/Zip/ZipItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO.Compression; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.IO.Zip 9 | { 10 | public class ZipItem 11 | { 12 | public ZipItem(ZipArchiveEntry entry) 13 | { 14 | ArgumentNullException.ThrowIfNull(entry, nameof(entry)); 15 | 16 | _entry = entry; 17 | } 18 | 19 | private readonly ZipArchiveEntry _entry; 20 | 21 | public long Length => _entry.Length; 22 | 23 | public string Name => _entry.Name; 24 | 25 | public string FullName => _entry.FullName; 26 | 27 | public Stream OpenStream() 28 | { 29 | return _entry.Open(); 30 | } 31 | 32 | public byte[] ReadAllBytes() 33 | { 34 | using Stream stream = _entry.Open(); 35 | byte[] result = new byte[stream.Length]; 36 | stream.Read(result, 0, result.Length); 37 | return result; 38 | } 39 | 40 | public string ReadAllText() 41 | { 42 | return ReadAllText(Encoding.UTF8); 43 | } 44 | 45 | public string ReadAllText(Encoding encoding) 46 | { 47 | using Stream stream = _entry.Open(); 48 | using StreamReader reader = new(stream, encoding); 49 | return reader.ReadToEnd(); 50 | } 51 | 52 | public string[] ReadAllLines() 53 | { 54 | return ReadAllLines(Encoding.UTF8); 55 | } 56 | 57 | public string[] ReadAllLines(Encoding encoding) 58 | { 59 | using Stream stream = _entry.Open(); 60 | using StreamReader reader = new(stream, encoding); 61 | List lines = []; 62 | 63 | string? line; 64 | while ((line = reader.ReadLine()) is not null) 65 | lines.Add(line); 66 | 67 | return lines.ToArray(); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /QuanLib.Logging/Log4NetLogger.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using QuanLib.Core; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.Logging 10 | { 11 | public class Log4NetLogger(ILog log) : ILogger 12 | { 13 | private readonly ILog _log = log; 14 | 15 | public void Debug(string message) => _log.Debug(message); 16 | 17 | public void Debug(string message, Exception exception) => _log.Debug(message, exception); 18 | 19 | public void Info(string message) => _log.Info(message); 20 | 21 | public void Info(string message, Exception exception) => _log.Info(message, exception); 22 | 23 | public void Warn(string message) => _log.Warn(message); 24 | 25 | public void Warn(string message, Exception exception) => _log.Warn(message, exception); 26 | 27 | public void Error(string message) => _log.Error(message); 28 | 29 | public void Error(string message, Exception exception) => _log.Error(message, exception); 30 | 31 | public void Fatal(string message) => _log.Fatal(message); 32 | 33 | public void Fatal(string message, Exception exception) => _log.Fatal(message, exception); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /QuanLib.Logging/LoggerGetter.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace QuanLib.Logging 11 | { 12 | public class LoggerGetter : ILoggerGetter 13 | { 14 | public LoggerGetter(LogManager owner) 15 | { 16 | ArgumentNullException.ThrowIfNull(owner, nameof(owner)); 17 | 18 | _owner = owner; 19 | } 20 | 21 | private readonly LogManager _owner; 22 | 23 | public ILogger GetLogger() => new Log4NetLogger(_owner.GetLogger()); 24 | 25 | public ILogger GetLogger(Type type) => new Log4NetLogger(_owner.GetLogger(type)); 26 | 27 | public ILogger GetLogger(string name) => new Log4NetLogger(_owner.GetLogger(name)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /QuanLib.Logging/QuanLib.Logging.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/AbbreviationBytesUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class AbbreviationBytesUnitText : BytesUnitText 10 | { 11 | public static readonly AbbreviationBytesUnitText Default = new(); 12 | 13 | public override string B => "B"; 14 | 15 | public override string KB => "K"; 16 | 17 | public override string MB => "M"; 18 | 19 | public override string GB => "G"; 20 | 21 | public override string TB => "T"; 22 | 23 | public override string PB => "P"; 24 | 25 | public override string EB => "E"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/AbbreviationTimeUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class AbbreviationTimeUnitText : TimeUnitText 10 | { 11 | public static readonly AbbreviationTimeUnitText Default = new(); 12 | 13 | public override string Tikc => "t"; 14 | 15 | public override string Microsecond => "us"; 16 | 17 | public override string Millisecond => "ms"; 18 | 19 | public override string Second => "s"; 20 | 21 | public override string Minute => "min"; 22 | 23 | public override string Hour => "h"; 24 | 25 | public override string Day => "d"; 26 | 27 | public override string Month => "mo"; 28 | 29 | public override string Year => "y"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/BytesFormatText.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.TextFormat 10 | { 11 | public abstract class BytesUnitText 12 | { 13 | public abstract string B { get; } 14 | 15 | public abstract string KB { get; } 16 | 17 | public abstract string MB { get; } 18 | 19 | public abstract string GB { get; } 20 | 21 | public abstract string TB { get; } 22 | 23 | public abstract string PB { get; } 24 | 25 | public abstract string EB { get; } 26 | 27 | public string Get(BytesUnit bytesUnit) 28 | { 29 | return bytesUnit switch 30 | { 31 | BytesUnit.B => B, 32 | BytesUnit.KB => KB, 33 | BytesUnit.MB => MB, 34 | BytesUnit.GB => GB, 35 | BytesUnit.TB => TB, 36 | BytesUnit.PB => PB, 37 | BytesUnit.EB => EB, 38 | _ => throw new InvalidEnumArgumentException(nameof(bytesUnit), (int)bytesUnit, typeof(BytesUnit)), 39 | }; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/ChineseBytesUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class ChineseBytesUnitText : BytesUnitText 10 | { 11 | public static readonly ChineseBytesUnitText Default = new(); 12 | 13 | public override string B => "字节"; 14 | 15 | public override string KB => "千字节"; 16 | 17 | public override string MB => "兆字节"; 18 | 19 | public override string GB => "吉字节"; 20 | 21 | public override string TB => "太字节"; 22 | 23 | public override string PB => "拍字节"; 24 | 25 | public override string EB => "艾字节"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/ChineseTimeUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class ChineseTimeUnitText : TimeUnitText 10 | { 11 | public static readonly ChineseTimeUnitText Default = new(); 12 | 13 | public override string Year => "年"; 14 | 15 | public override string Month => "个月"; 16 | 17 | public override string Day => "天"; 18 | 19 | public override string Hour => "小时"; 20 | 21 | public override string Minute => "分钟"; 22 | 23 | public override string Second => "秒"; 24 | 25 | public override string Millisecond => "毫秒"; 26 | 27 | public override string Microsecond => "微妙"; 28 | 29 | public override string Tikc => "刻"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/EnglishBytesUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class EnglishBytesUnitText : BytesUnitText 10 | { 11 | public static readonly EnglishBytesUnitText Default = new(); 12 | 13 | public override string B => "Bytes"; 14 | 15 | public override string KB => "KiloBytes"; 16 | 17 | public override string MB => "MegaBytes"; 18 | 19 | public override string GB => "Gigabytes"; 20 | 21 | public override string TB => "TeraBytes"; 22 | 23 | public override string PB => "PetaBytes"; 24 | 25 | public override string EB => "ExaBytes"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/EnglishTimeUnitText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public class EnglishTimeUnitText : TimeUnitText 10 | { 11 | public static readonly EnglishTimeUnitText Default = new(); 12 | 13 | public override string Tikc => "Tikcs"; 14 | 15 | public override string Microsecond => "Microseconds"; 16 | 17 | public override string Millisecond => "Milliseconds"; 18 | 19 | public override string Second => "Seconds"; 20 | 21 | public override string Minute => "Minutes"; 22 | 23 | public override string Hour => "Hours"; 24 | 25 | public override string Day => "Days"; 26 | 27 | public override string Month => "Months"; 28 | 29 | public override string Year => "Years"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/QuanLib.TextFormat.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/TextFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace QuanLib.TextFormat 8 | { 9 | public enum TextFormat 10 | { 11 | StaticDecimals, 12 | 13 | DynamicDecimals, 14 | 15 | MultipleUnits 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /QuanLib.TextFormat/TimeUnitText.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.TextFormat 10 | { 11 | public abstract class TimeUnitText 12 | { 13 | public abstract string Tikc { get; } 14 | 15 | public abstract string Microsecond { get; } 16 | 17 | public abstract string Millisecond { get; } 18 | 19 | public abstract string Second { get; } 20 | 21 | public abstract string Minute { get; } 22 | 23 | public abstract string Hour { get; } 24 | 25 | public abstract string Day { get; } 26 | 27 | public abstract string Month { get; } 28 | 29 | public abstract string Year { get; } 30 | 31 | public string Get(TimeUnit timeUnit) 32 | { 33 | return timeUnit switch 34 | { 35 | TimeUnit.Tikc => Tikc, 36 | TimeUnit.Microsecond => Microsecond, 37 | TimeUnit.Millisecond => Millisecond, 38 | TimeUnit.Second => Second, 39 | TimeUnit.Minute => Minute, 40 | TimeUnit.Hour => Hour, 41 | TimeUnit.Day => Day, 42 | TimeUnit.Month => Month, 43 | TimeUnit.Year => Year, 44 | _ => throw new InvalidEnumArgumentException(nameof(timeUnit), (int)timeUnit, typeof(TimeUnit)), 45 | }; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /QuanLib.TomlConfig/QuanLib.TomlConfig.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/ConstructorView.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.VisualObject 10 | { 11 | public class ConstructorView 12 | { 13 | public ConstructorView(ConstructorInfo constructorInfo) 14 | { 15 | ArgumentNullException.ThrowIfNull(constructorInfo, nameof(constructorInfo)); 16 | 17 | ConstructorInfo = constructorInfo; 18 | } 19 | 20 | public ConstructorInfo ConstructorInfo { get; } 21 | 22 | public AccessModifier AccessModifier => ConstructorInfo.GetAccessModifier(); 23 | 24 | public override string ToString() 25 | { 26 | StringBuilder stringBuilder = new(); 27 | 28 | stringBuilder.Append(AccessModifier.ToString()); 29 | stringBuilder.Append(' '); 30 | stringBuilder.Append(ObjectFormatter.Format(ConstructorInfo.DeclaringType).Split('.')[^1]); 31 | stringBuilder.Append('('); 32 | stringBuilder.AppendJoin(", ", ConstructorInfo.GetParameters().Select(s => new ParameterView(s))); 33 | stringBuilder.Append(')'); 34 | 35 | return stringBuilder.ToString(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/FieldView.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.VisualObject 10 | { 11 | public class FieldView 12 | { 13 | public FieldView(FieldInfo fieldInfo, object? obj) 14 | { 15 | ArgumentNullException.ThrowIfNull(fieldInfo, nameof(fieldInfo)); 16 | 17 | FieldInfo = fieldInfo; 18 | _obj = obj; 19 | } 20 | 21 | private readonly object? _obj; 22 | 23 | public FieldInfo FieldInfo { get; } 24 | 25 | public AccessModifier AccessModifier => FieldInfo.GetAccessModifier(); 26 | 27 | public MemberValue GetValue() 28 | { 29 | return MemberValue.GetValue(FieldInfo, _obj); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | MemberValue memberValue = GetValue(); 35 | StringBuilder stringBuilder = new(); 36 | 37 | stringBuilder.Append(AccessModifier.ToCodeString()); 38 | stringBuilder.Append(' '); 39 | 40 | if (FieldInfo.IsStatic) 41 | stringBuilder.Append("static "); 42 | 43 | if (FieldInfo.IsInitOnly) 44 | stringBuilder.Append("readonly "); 45 | 46 | stringBuilder.Append(ObjectFormatter.Format(memberValue.MemberType)); 47 | 48 | if (memberValue.ValueType != memberValue.MemberType) 49 | stringBuilder.AppendFormat("({0})", ObjectFormatter.Format(memberValue.ValueType)); 50 | 51 | stringBuilder.Append(' '); 52 | stringBuilder.Append(FieldInfo.Name); 53 | 54 | stringBuilder.AppendFormat(" = {{{0}}}", ObjectFormatter.Format(memberValue.Value)); 55 | 56 | return stringBuilder.ToString(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/MemberValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace QuanLib.VisualObject 9 | { 10 | public class MemberValue 11 | { 12 | public MemberValue(Type memberType, object? value, bool throwException) 13 | { 14 | ArgumentNullException.ThrowIfNull(memberType, nameof(memberType)); 15 | 16 | MemberType = memberType; 17 | ValueType = value?.GetType() ?? memberType; 18 | Value = value; 19 | ThrownException = throwException; 20 | } 21 | 22 | public Type MemberType { get; } 23 | 24 | public Type ValueType { get; } 25 | 26 | public object? Value { get; } 27 | 28 | public bool ThrownException { get; } 29 | 30 | public static MemberValue GetValue(FieldInfo fieldInfo, object? obj) 31 | { 32 | ArgumentNullException.ThrowIfNull(fieldInfo, nameof(fieldInfo)); 33 | 34 | object? value = fieldInfo.GetValue(obj); 35 | return new(fieldInfo.FieldType, value, false); 36 | } 37 | 38 | public static MemberValue GetValue(PropertyInfo propertyInfo, object? obj) 39 | { 40 | ArgumentNullException.ThrowIfNull(propertyInfo, nameof(propertyInfo)); 41 | 42 | try 43 | { 44 | object? value = propertyInfo.GetValue(obj); 45 | return new(propertyInfo.PropertyType, value, false); 46 | } 47 | catch (Exception ex) 48 | { 49 | return new(propertyInfo.PropertyType, ex, true); 50 | } 51 | } 52 | 53 | public static MemberValue GetValue(MethodInfo methodInfo, object? obj, object?[]? parameters) 54 | { 55 | ArgumentNullException.ThrowIfNull(methodInfo, nameof(methodInfo)); 56 | 57 | try 58 | { 59 | object? value = methodInfo.Invoke(obj, parameters); 60 | return new(methodInfo.ReturnType, value, false); 61 | } 62 | catch (Exception ex) 63 | { 64 | return new(methodInfo.ReturnType, ex, true); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/MethodView.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.VisualObject 10 | { 11 | public class MethodView 12 | { 13 | public MethodView(MethodInfo methodInfo, object? obj) 14 | { 15 | ArgumentNullException.ThrowIfNull(methodInfo, nameof(methodInfo)); 16 | 17 | MethodInfo = methodInfo; 18 | _obj = obj; 19 | } 20 | 21 | private readonly object? _obj; 22 | 23 | public MethodInfo MethodInfo { get; } 24 | 25 | public AccessModifier AccessModifier => MethodInfo.GetAccessModifier(); 26 | 27 | public MemberValue GetValue(object?[]? parameters) 28 | { 29 | return MemberValue.GetValue(MethodInfo, _obj, parameters); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | StringBuilder stringBuilder = new(); 35 | 36 | stringBuilder.Append(AccessModifier.ToCodeString()); 37 | stringBuilder.Append(' '); 38 | 39 | if (MethodInfo.IsStatic) 40 | stringBuilder.Append("static "); 41 | 42 | stringBuilder.Append(ObjectFormatter.Format(MethodInfo.ReturnType)); 43 | stringBuilder.Append(' '); 44 | stringBuilder.Append(MethodInfo.Name); 45 | stringBuilder.Append('('); 46 | stringBuilder.AppendJoin(", ", MethodInfo.GetParameters().Select(s => new ParameterView(s))); 47 | stringBuilder.Append(')'); 48 | 49 | return stringBuilder.ToString(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/ParameterView.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.VisualObject 10 | { 11 | public class ParameterView 12 | { 13 | public ParameterView(ParameterInfo parameterInfo) 14 | { 15 | ArgumentNullException.ThrowIfNull(parameterInfo, nameof(parameterInfo)); 16 | 17 | ParameterInfo = parameterInfo; 18 | } 19 | 20 | public ParameterInfo ParameterInfo { get; } 21 | 22 | public override string ToString() 23 | { 24 | StringBuilder stringBuilder = new(); 25 | 26 | if (ParameterInfo.ParameterType.IsByRef) 27 | { 28 | if (ParameterInfo.IsIn) 29 | stringBuilder.Append("in"); 30 | else if (ParameterInfo.IsOut) 31 | stringBuilder.Append("out"); 32 | else 33 | stringBuilder.Append("ref"); 34 | stringBuilder.Append(' '); 35 | } 36 | 37 | stringBuilder.Append(ObjectFormatter.Format(ParameterInfo.ParameterType)); 38 | stringBuilder.Append(' '); 39 | stringBuilder.Append(ParameterInfo.Name); 40 | 41 | if (ParameterInfo.HasDefaultValue) 42 | { 43 | stringBuilder.Append(" = "); 44 | stringBuilder.Append(ObjectFormatter.Format(ParameterInfo.DefaultValue)); 45 | } 46 | 47 | return stringBuilder.ToString(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/PropertyView.cs: -------------------------------------------------------------------------------- 1 | using QuanLib.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace QuanLib.VisualObject 10 | { 11 | public class PropertyView 12 | { 13 | public PropertyView(PropertyInfo propertyInfo, object? obj) 14 | { 15 | ArgumentNullException.ThrowIfNull(propertyInfo, nameof(propertyInfo)); 16 | 17 | PropertyInfo = propertyInfo; 18 | _obj = obj; 19 | } 20 | 21 | private readonly object? _obj; 22 | 23 | public PropertyInfo PropertyInfo { get; } 24 | 25 | public AccessModifier AccessModifier => PropertyInfo.GetAccessModifier(); 26 | 27 | public bool IsStatic => PropertyInfo.IsStatic(); 28 | 29 | public MemberValue GetValue() 30 | { 31 | return MemberValue.GetValue(PropertyInfo, _obj); 32 | } 33 | 34 | public override string ToString() 35 | { 36 | MemberValue memberValue = GetValue(); 37 | StringBuilder stringBuilder = new(); 38 | 39 | stringBuilder.Append(AccessModifier.ToCodeString()); 40 | stringBuilder.Append(' '); 41 | 42 | if (IsStatic) 43 | stringBuilder.Append("static "); 44 | 45 | stringBuilder.Append(ObjectFormatter.Format(memberValue.MemberType)); 46 | 47 | if (memberValue.ValueType != memberValue.MemberType) 48 | stringBuilder.AppendFormat("({0})", ObjectFormatter.Format(memberValue.ValueType)); 49 | 50 | stringBuilder.Append(' '); 51 | stringBuilder.Append(PropertyInfo.Name); 52 | stringBuilder.Append(" { "); 53 | 54 | if (PropertyInfo.GetMethod is MethodInfo getMethod) 55 | { 56 | AccessModifier accessModifier = getMethod.GetAccessModifier(); 57 | if (accessModifier != AccessModifier) 58 | { 59 | stringBuilder.Append(accessModifier.ToCodeString()); 60 | stringBuilder.Append(' '); 61 | } 62 | 63 | stringBuilder.Append("get; "); 64 | } 65 | 66 | if (PropertyInfo.SetMethod is MethodInfo setMethod) 67 | { 68 | AccessModifier accessModifier = setMethod.GetAccessModifier(); 69 | if (accessModifier != AccessModifier) 70 | { 71 | stringBuilder.Append(accessModifier.ToCodeString()); 72 | stringBuilder.Append(' '); 73 | } 74 | 75 | stringBuilder.Append("set; "); 76 | } 77 | 78 | stringBuilder.AppendFormat("}} = {{{0}}}", ObjectFormatter.Format(memberValue.Value)); 79 | 80 | return stringBuilder.ToString(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /QuanLib.VisualObject/QuanLib.VisualObject.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuanLib --------------------------------------------------------------------------------