mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-18 01:16:44 +08:00
重置文件,准备升级版本
This commit is contained in:
341
.gitignore
vendored
Normal file
341
.gitignore
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
|
||||
**/wwwroot/lib/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
301
README.md
Normal file
301
README.md
Normal file
@@ -0,0 +1,301 @@
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p align="center">
|
||||
<img src="https://ftp.bmp.ovh/imgs/2021/06/351eeccfadc07014.png" width = "100" height = "100" alt="图片名称" align=center />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://www.nuget.org/packages/RRQMSocket/)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://www.nuget.org/packages/RRQMSocket/)
|
||||
[](https://gitee.com/dotnetchina/RRQMSocket/stargazers)
|
||||
[](https://gitee.com/dotnetchina/RRQMSocket/members)
|
||||
<a href="https://jq.qq.com/?_wv=1027&k=gN7UL4fw">
|
||||
<img src="https://img.shields.io/badge/QQ群-234762506-red" alt="QQ">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
合抱之木,生于毫末;九层之台,起于垒土。
|
||||
|
||||
</div>
|
||||
|
||||
## 🎀描述
|
||||
| 名称|地址 |描述|
|
||||
|---|---|---|
|
||||
|[](https://www.nuget.org/packages/RRQMSocket/)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket)| RRQMSocket是一个整合性的、超轻量级的网络通信框架。<br>包含了TCP、UDP、Ssl、Channel、Protocol、Token、<br>租户模式等一系列的通信模块。其扩展组件包含:WebSocket、<br>大文件传输、RPC、WebApi、XmlRpc、JsonRpc等内容|
|
||||
|[](https://www.nuget.org/packages/RRQMSocketFramework/)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) |**RRQMSocketFramework**是RRQMSocket系列的增强企业版,<br>两者在基础功能上没有区别,但是在扩展功能上有一定差异性,<br>例如RPC中的EventBus、文件传输中的限速功能等,<br>具体差异请看[RRQM商业运营](https://www.yuque.com/eo2w71/rrqm/80696720a95e415d94c87fa03642513d)|
|
||||
| [](https://www.nuget.org/packages/RRQMCore)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) | RRQMCore是为RRQM系提供基础服务功能的库,其中包含:<br>**内存池**、**对象池**、**等待逻辑池**、**AppMessenger**、**3DES加密**、<br>**Xml快速存储**、**运行时间测量器**、**文件快捷操作**、<br>**高性能序列化器**、**规范日志接口**等。 |
|
||||
| [](https://www.nuget.org/packages/rrqmsocket.websocket)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) | RRQMSocket.WebSocket是一个高效,超轻量级的WebSocket框架。<br>它包含了Service和Client两大组件,支持Ssl,同时定义了文本、二进制或<br>其他类型数据的快捷发送、分片发送接口,可与js等任意WebSocket组件交互|
|
||||
| [](https://www.nuget.org/packages/rrqmsocket.http)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) | RRQMSocket.Http是一个能够简单解析Http的服务组件,<br>能够快速响应Http服务请求。|
|
||||
|[](https://www.nuget.org/packages/rrqmsocket.rpc)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) |RPC是一个超轻量、高性能、可扩展的微服务管理平台框架,<br>目前已完成开发**RRQMRPC**、**XmlRpc**、**JsonRpc**、**WebApi**部分。<br> **RRQMRPC**部分使用RRQM专属协议,支持客户端**异步调用**,<br>服务端**异步触发**、以及**out**和**ref**关键字,**函数回调**等。<br>在调用效率上也是非常强悍,在调用空载函数,且返回状态时,<br>**10w**次调用仅用时**3.8**秒,不返回状态用时**0.9**秒。<br>其他协议调用性能详看性能评测。
|
||||
|[](https://www.nuget.org/packages/rrqmsocket.rpc.xmlrpc)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket)| XmlRpc是一个扩展于RRQMSocket.RPC的XmlRpc组件,可以通过<br>该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,<br>Array等,也能与CookComputing.XmlRpcV2完美对接。<br>不限Web,Android等平台。|
|
||||
| [](https://www.nuget.org/packages/rrqmsocket.rpc.jsonrpc)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket)| JsonRpc是一个扩展于RRQMSocket.RPC的JsonRpc组件,<br>可以通过该组件创建JsonRpc服务解析器,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。|
|
||||
|[](https://www.nuget.org/packages/rrqmsocket.rpc.webapi)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket)| WebApi是一个扩展于RRQMSocket.RPC的WebApi组件,可以通过<br>该组件创建WebApi服务解析器,让桌面端、Web端、移动端可以<br>跨语言调用RPC函数。功能支持路由、Get传参、Post传参等。|
|
||||
| [](https://www.nuget.org/packages/rrqmsocket.filetransfer)|[Gitee](https://gitee.com/dotnetchina/RRQMSocket)<br>[Github](https://github.com/RRQM/RRQMSocket) | 这是一个高性能的C/S架构的文件传输框架,您可以用它传输<br>**任意大小**的文件,它可以完美支持**上传下载混合式队列传输**、<br>**断点续传**、 **快速上传** 、**传输限速**、**获取文件信息**、**删除文件**等。<br>在实际测试中,它的传输速率可达1000Mb/s。 |
|
||||
|
||||
|
||||
## 🖥支持环境
|
||||
- .NET Framework4.5及以上。
|
||||
- .NET Core3.1及以上。
|
||||
- .NET Standard2.0及以上。
|
||||
|
||||
## 🥪支持框架
|
||||
- WPF
|
||||
- Winform
|
||||
- Blazor
|
||||
- Xamarin
|
||||
- Mono
|
||||
- Unity(在IL2cpp编译时,需要导入源码,Mono则直接加载dll即可)
|
||||
- 其他(即所有C#系)
|
||||
|
||||
## 🌴RRQMSocket特点速览
|
||||
|
||||
#### 传统IOCP和RRQMSocket
|
||||
|
||||
RRQMSocket的IOCP和传统也不一样,就以微软官方示例为例,使用MemoryBuffer开辟一块内存,均分,然后给每个会话分配一个区接收,等收到数据后,再**复制**源数据,然后把复制的数据进行处理。而RRQMSocket是每次接收之前,从内存池拿一个可用内存块,然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**1000w**次**64kb**的数据时,性能相差了**10倍**。
|
||||
|
||||
#### 数据处理适配器
|
||||
|
||||
相信大家都使用过其他的Socket产品,那么RRQMSocket在设计时也是借鉴了其他产品的优秀设计理念,数据处理适配器就是其中之一,但和其他产品的设计不同的是,RRQMSocket的适配器功能更加强大,它不仅可以提前解析数据包,还可以解析数据对象。例如:可以使用固定包头对数据进行预处理,从而解决**数据分包**、**粘包**的问题。也可以直接解析**HTTP**数据协议、WebSocket数据协议等。
|
||||
|
||||
#### 兼容性与适配
|
||||
|
||||
RRQMSocket提供多种框架模型,能够完全兼容基于TCP、UDP协议的所有协议。例如:TcpService与TcpClient,其基础功能和Socket一模一样,只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。
|
||||
|
||||
## 🔗联系作者
|
||||
|
||||
- [CSDN博客主页](https://blog.csdn.net/qq_40374647)
|
||||
- [哔哩哔哩视频](https://space.bilibili.com/94253567)
|
||||
- [源代码仓库主页](https://gitee.com/RRQM_Home)
|
||||
- 交流QQ群:234762506
|
||||
|
||||
## 🌟API手册
|
||||
- [ API首页 ](https://www.yuque.com/eo2w71/rrqm/2c5dab34026d2b45ada6e51ae9e51a5a)
|
||||
|
||||
## ✨简单示例
|
||||
|
||||
**_以下仅以最简方式创建示例,更多详情请查看[API文档](https://www.yuque.com/eo2w71/rrqm/2c5dab34026d2b45ada6e51ae9e51a5a)。_**
|
||||
|
||||
**【TcpService】**
|
||||
|
||||
```
|
||||
TcpService service = new TcpService();
|
||||
service.Connecting += (client, e) =>{};//有客户端正在连接
|
||||
service.Connected += (client, e) =>{};//有客户端连接
|
||||
service.Disconnected += (client, e) =>{};//有客户端断开连接
|
||||
service.Received += (client, byteBlock, obj) =>
|
||||
{
|
||||
//从客户端收到信息
|
||||
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
|
||||
Console.WriteLine($"已从{client.Name}接收到信息:{mes}");//Name即IP+Port
|
||||
};
|
||||
//声明配置
|
||||
var config = new TcpServiceConfig();
|
||||
config.ListenIPHosts = new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) };//同时监听两个地址
|
||||
//载入配置
|
||||
service.Setup(config);
|
||||
//启动
|
||||
service.Start();
|
||||
```
|
||||
|
||||
**【TcpClient】**
|
||||
```
|
||||
SimpleTcpClient tcpClient = new SimpleTcpClient();
|
||||
tcpClient.Connected += (client, e) =>{};//成功连接到服务器
|
||||
tcpClient.Disconnected += (client, e) =>{};//从服务器断开连接,当连接不成功时不会触发。
|
||||
//载入配置
|
||||
tcpClient.Setup("127.0.0.1:7789");
|
||||
tcpClient.Connect();
|
||||
tcpClient.Send(Encoding.UTF8.GetBytes("RRQM"));
|
||||
```
|
||||
|
||||
**【TcpClient 断线重连】**
|
||||
|
||||
```
|
||||
tcpClient.UseReconnection(tryCount:5,printLog:true);
|
||||
```
|
||||
|
||||
**【FixedHeaderPackageAdapter包模式】**
|
||||
|
||||
该适配器主要解决TCP粘分包问题,数据格式采用简单而高效的“包头+数据体”的模式,其中包头支持:
|
||||
|
||||
- Byte模式(1+n),一次性最大接收255字节的数据。
|
||||
- Ushort模式(2+n),一次最大接收65535字节。
|
||||
- Int模式(4+n),一次最大接收2G数据。
|
||||
|
||||
以上数据头均采用RRQMBitConverter的默认端模式(小端模式),使用者可以根据需求切换默认端模式。
|
||||
|
||||
```
|
||||
RRQMBitConverter.DefaultEndianType = EndianType.Little;
|
||||
```
|
||||
|
||||
**【CustomFixedHeaderDataHandlingAdapter】**
|
||||
|
||||
用户自定义固定包头适配器,主要帮助用户解决具有固定包头的数据帧信息。例如:下列数据格式,仅需要实现几个接口,就能完成解析,详细操作请参照API。
|
||||
|
||||
|1|1|1|**********|
|
||||
|
||||
**【CustomUnfixedHeaderDataHandlingAdapter】**
|
||||
|
||||
用户自定义不固定包头适配器,主要帮助用户解决具有包头不固定的数据帧信息。例如:最典型的HTTP数据包,其数据头和数据体由“\r\n”隔开,而数据头又因为请求者的请求信息的不同,头部数据也不固定,而数据体的长度,也是由数据头的ContentLength的值显式指定的,所以可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析,也是仅通过简单的开发,就能实现。
|
||||
|
||||
|
||||
**【Ssl加密】**
|
||||
|
||||
在[RRQMBox](https://gitee.com/RRQM_Home/RRQMBox/tree/master/Ssl%E8%AF%81%E4%B9%A6%E7%9B%B8%E5%85%B3)中,放置了一个自制Ssl证书,密码为“RRQMSocket”以供测试。使用配置非常方便。
|
||||
|
||||
在服务器中只需设置配置SslOption属性和接收模式(接收模式在Ssl模式下只支持BIO和Select)。
|
||||
|
||||
**服务器配置**
|
||||
```
|
||||
config.SslOption = new ServiceSslOption() { Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), SslProtocols = SslProtocols.Tls12 };
|
||||
config.ReceiveType = ReceiveType.Select;
|
||||
```
|
||||
|
||||
**客户端配置**
|
||||
|
||||
```
|
||||
config.ReceiveType = ReceiveType.BIO;
|
||||
config.SslOption = new ClientSslOption()
|
||||
{
|
||||
ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },
|
||||
SslProtocols = SslProtocols.Tls12,
|
||||
TargetHost = "127.0.0.1",
|
||||
CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }
|
||||
};
|
||||
```
|
||||
|
||||
**【WS服务器】**
|
||||
|
||||
```
|
||||
WSService wSService = new WSService();
|
||||
wSService.Received += WSService_Received;
|
||||
wSService.Connected += WSService_Connected;
|
||||
|
||||
var config = new WSServiceConfig();
|
||||
config.ListenIPHosts = new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) };//同时监听两个地址
|
||||
config.ReceiveType = ReceiveType.IOCP;
|
||||
|
||||
wSService.Setup(config).Start();
|
||||
Console.WriteLine("WS服务器已启动");
|
||||
```
|
||||
|
||||
**【WSs服务器】**
|
||||
|
||||
创建WSs服务器时,其他配置不变,只需要在`config`中加入以下代码即可。
|
||||
|
||||
在[RRQMBox](https://gitee.com/RRQM_Home/RRQMBox/tree/master/Ssl%E8%AF%81%E4%B9%A6%E7%9B%B8%E5%85%B3)中,放置了一个自制Ssl证书,密码为“RRQMSocket”以供测试。使用配置非常方便。
|
||||
```csharp
|
||||
//config.SslOption = new ServiceSslOption() { Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), SslProtocols = SslProtocols.Tls12 };//Ssl配置,当为null的时候,相当于创建了ws服务器,当赋值的时候,相当于wss服务器。
|
||||
config.ReceiveType = ReceiveType.Select;//在没有ssl配置时,请使用IOCP模式,速度会好些,使用ssl时,可以选择Select和BIO,区别请看API
|
||||
```
|
||||
|
||||
**【WS客户端】**
|
||||
```csharp
|
||||
SimpleWSClient client = new SimpleWSClient();
|
||||
WSClientConfig config = new WSClientConfig();
|
||||
config.RemoteIPHost = new IPHost("127.0.0.1:7789");
|
||||
client .Setup(config);
|
||||
client .Connect();
|
||||
Console.WriteLine("连接成功");
|
||||
while (true)
|
||||
{
|
||||
client.Send(Console.ReadLine());
|
||||
}
|
||||
```
|
||||
***注意:当使用域名连接时,IPHost中的字符串必须显式指定端口,例如百度地址:IPHost("ws://baidu.com:80")***
|
||||
|
||||
|
||||
**【WSs客户端】**
|
||||
|
||||
同样的,在客户端配置中,只需要加入以下代码即可。
|
||||
|
||||
***注意:当使用域名连接时,TargetHost为域名,例如连接到IPHost("ws://baidu.com:80")时,TargetHost应当填写:baidu.com***
|
||||
```csharp
|
||||
config.SslOption = new ClientSslOption()
|
||||
{
|
||||
ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },
|
||||
SslProtocols = SslProtocols.Tls12,
|
||||
TargetHost = "127.0.0.1",
|
||||
CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }
|
||||
};
|
||||
config.ReceiveType = ReceiveType.BIO;
|
||||
```
|
||||
|
||||
**【WS 接收数据(服务器、客户端均可用)】**
|
||||
|
||||
```
|
||||
private static void MyWSClient_Received(IWSClientBase client, WSDataFrame dataFrame)
|
||||
{
|
||||
switch (dataFrame.Opcode)
|
||||
{
|
||||
case WSDataType.Cont:
|
||||
Console.WriteLine($"收到中间数据,长度为:{dataFrame.PayloadLength}");
|
||||
break;
|
||||
case WSDataType.Text:
|
||||
Console.WriteLine(dataFrame.GetMessage());
|
||||
break;
|
||||
case WSDataType.Binary:
|
||||
if (dataFrame.FIN)
|
||||
{
|
||||
Console.WriteLine($"收到二进制数据,长度为:{dataFrame.PayloadLength}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"收到未结束的二进制数据,长度为:{dataFrame.PayloadLength}");
|
||||
}
|
||||
break;
|
||||
case WSDataType.Close:
|
||||
break;
|
||||
case WSDataType.Ping:
|
||||
break;
|
||||
case WSDataType.Pong:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**【RPC调用】**
|
||||
|
||||
- WebApi:下列服务,可让浏览器通过`url/XUnitTestServer/Sum?a=10&b=20`来调用,结果可选xml或json。
|
||||
- JsonRpc:下列服务,可让普通TCP使用`{"jsonrpc":"2.0","method":"Sum","params":[10,20],"id":1}`来调用,也能让web通过http/https来调用。
|
||||
- xmlRpc:下列服务,可通过http+xml的形式调用。
|
||||
- RRQMRPC:使用专有协议调用。
|
||||
|
||||
**_其中除WebApi之外,其他调用均可生成C#代理调用。_**
|
||||
|
||||
```
|
||||
[Route("/[controller]/[action]")]
|
||||
public class XUnitTestServer : ControllerBase
|
||||
{
|
||||
|
||||
[XmlRpc]
|
||||
[JsonRpc]
|
||||
[Route]
|
||||
[RRQMRPC]
|
||||
public int Sum(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 🧲应用场景模拟
|
||||
[场景入口](https://www.yuque.com/eo2w71/rrqm/b138b52168853afb65369ca8171f14b9)
|
||||
|
||||
***
|
||||
|
||||
## 致谢
|
||||
|
||||
谢谢大家对我的支持,如果还有其他问题,请加群QQ:234762506讨论。
|
||||
|
||||
## 支持作者
|
||||
|
||||
[支持入口](https://www.yuque.com/eo2w71/rrqm/a5199820843b324f025633fdeee44394)
|
||||
917
RRQMCore/ByteManager/ByteBlock.cs
Normal file
917
RRQMCore/ByteManager/ByteBlock.cs
Normal file
@@ -0,0 +1,917 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMCore.Serialization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.ByteManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 字节块流
|
||||
/// </summary>
|
||||
public sealed class ByteBlock : Stream, IDisposable
|
||||
{
|
||||
internal bool @using;
|
||||
|
||||
internal long length;
|
||||
|
||||
private static float ratio = 1.5f;
|
||||
|
||||
private byte[] _buffer;
|
||||
|
||||
private bool holding;
|
||||
|
||||
private long position;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <param name="equalSize"></param>
|
||||
public ByteBlock(int byteSize = 1024 * 10, bool equalSize = false) : this(BytePool.GetByteCore(byteSize, equalSize))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 还能读取的长度,计算为<see cref="Len"/>与<see cref="Pos"/>的差值。
|
||||
/// </summary>
|
||||
public int CanReadLen
|
||||
{
|
||||
get { return this.Len - this.Pos; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 还能读取的长度,计算为<see cref="Len"/>与<see cref="Pos"/>的差值。
|
||||
/// </summary>
|
||||
public long CanReadLength
|
||||
{
|
||||
get { return this.length - this.position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
internal ByteBlock(byte[] bytes)
|
||||
{
|
||||
this.@using = true;
|
||||
this._buffer = bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩容增长比,默认为1.5,
|
||||
/// min:1.5
|
||||
/// </summary>
|
||||
public static float Ratio
|
||||
{
|
||||
get { return ratio; }
|
||||
set
|
||||
{
|
||||
if (value < 1.5)
|
||||
{
|
||||
value = 1.5f;
|
||||
}
|
||||
ratio = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 字节实例
|
||||
/// </summary>
|
||||
public byte[] Buffer
|
||||
{
|
||||
get { return this._buffer; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 可读取
|
||||
/// </summary>
|
||||
public override bool CanRead => this.@using;
|
||||
|
||||
/// <summary>
|
||||
/// 支持查找
|
||||
/// </summary>
|
||||
public override bool CanSeek => this.@using;
|
||||
|
||||
/// <summary>
|
||||
/// 可写入
|
||||
/// </summary>
|
||||
public override bool CanWrite => this.@using;
|
||||
|
||||
/// <summary>
|
||||
/// 容量
|
||||
/// </summary>
|
||||
public int Capacity => this._buffer.Length;
|
||||
|
||||
/// <summary>
|
||||
/// 表示持续性持有,为True时,Dispose将调用无效。
|
||||
/// </summary>
|
||||
public bool Holding
|
||||
{
|
||||
get { return this.holding; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Int真实长度
|
||||
/// </summary>
|
||||
public int Len
|
||||
{ get { return (int)this.length; } }
|
||||
|
||||
/// <summary>
|
||||
/// 真实长度
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{ get { return this.length; } }
|
||||
|
||||
/// <summary>
|
||||
/// int型流位置
|
||||
/// </summary>
|
||||
public int Pos
|
||||
{
|
||||
get { return (int)this.position; }
|
||||
set { this.position = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流位置
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return this.position; }
|
||||
set { this.position = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用状态
|
||||
/// </summary>
|
||||
public bool Using
|
||||
{
|
||||
get { return this.@using; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接完全释放,游离该对象,然后等待GC
|
||||
/// </summary>
|
||||
public void AbsoluteDispose()
|
||||
{
|
||||
this.holding = false;
|
||||
this.@using = false;
|
||||
this.position = 0;
|
||||
this.length = 0;
|
||||
this._buffer = default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空数据
|
||||
/// </summary>
|
||||
/// <exception cref="ByteBlockDisposedException">内存块已释放</exception>
|
||||
public void Clear()
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
Array.Clear(this._buffer, 0, this._buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收资源
|
||||
/// </summary>
|
||||
public new void Dispose()
|
||||
{
|
||||
if (this.holding)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.@using)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (this.@using)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
BytePool.Recycle(this._buffer);
|
||||
this.AbsoluteDispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无实际效果
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
int len = this._buffer.Length - this.position > count ? count : this._buffer.Length - (int)this.position;
|
||||
Array.Copy(this._buffer, this.position, buffer, offset, len);
|
||||
this.position += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取数据
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <returns></returns>
|
||||
public int Read(byte[] buffer)
|
||||
{
|
||||
return this.Read(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置流位置
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="origin"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
this.position = offset;
|
||||
break;
|
||||
|
||||
case SeekOrigin.Current:
|
||||
this.position += offset;
|
||||
break;
|
||||
|
||||
case SeekOrigin.End:
|
||||
this.position = this.length + offset;
|
||||
break;
|
||||
}
|
||||
return this.position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新设置容量
|
||||
/// </summary>
|
||||
/// <param name="size">新尺寸</param>
|
||||
/// <param name="retainedData">是否保留元数据</param>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public void SetCapacity(int size, bool retainedData = false)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
byte[] bytes = new byte[size];
|
||||
|
||||
if (retainedData)
|
||||
{
|
||||
Array.Copy(this._buffer, 0, bytes, 0, this._buffer.Length);
|
||||
}
|
||||
BytePool.Recycle(this._buffer);
|
||||
this._buffer = bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置持续持有属性,当为True时,调用Dispose会失效,表示该对象将长期持有,直至设置为False。
|
||||
/// 当为False时,会自动调用Dispose。
|
||||
/// </summary>
|
||||
/// <param name="holding"></param>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public void SetHolding(bool holding)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
this.holding = holding;
|
||||
if (!holding)
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置实际长度
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
if (value > this._buffer.Length)
|
||||
{
|
||||
throw new RRQMException("设置值超出容量");
|
||||
}
|
||||
this.length = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为有效内存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
return this.ToArray(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从指定位置转化到有效内存
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public byte[] ToArray(int offset)
|
||||
{
|
||||
return this.ToArray(offset, (int)(this.length - offset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从指定位置转化到指定长度的有效内存
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] ToArray(int offset, int length)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
byte[] buffer = new byte[length];
|
||||
Array.Copy(this._buffer, offset, buffer, 0, buffer.Length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (!this.@using)
|
||||
{
|
||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
||||
}
|
||||
if (this._buffer.Length - this.position < count)
|
||||
{
|
||||
int need = this._buffer.Length + count - ((int)(this._buffer.Length - this.position));
|
||||
int lend = this._buffer.Length;
|
||||
while (need > lend)
|
||||
{
|
||||
lend = (int)(lend * ratio);
|
||||
}
|
||||
this.SetCapacity(lend, true);
|
||||
}
|
||||
Array.Copy(buffer, offset, this._buffer, this.position, count);
|
||||
this.position += count;
|
||||
this.length += count;
|
||||
if (this.length < this.position)
|
||||
{
|
||||
this.length = this.position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <returns></returns>
|
||||
public void Write(byte[] buffer)
|
||||
{
|
||||
this.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
#region BytesPackage
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个独立的<see cref="byte"/>数组包
|
||||
/// </summary>
|
||||
public byte[] ReadBytesPackage()
|
||||
{
|
||||
byte status = this.ReadByte();
|
||||
if (status == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int length = this.ReadInt32();
|
||||
byte[] data = new byte[length];
|
||||
Array.Copy(this._buffer, this.position, data, 0, length);
|
||||
this.position += length;
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取数据包信息,方便从Buffer操作数据
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryReadBytesPackageInfo(out int pos, out int len)
|
||||
{
|
||||
byte status = this.ReadByte();
|
||||
if (status == 0)
|
||||
{
|
||||
pos = 0;
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
len = this.ReadInt32();
|
||||
pos = (int)this.position;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入一个独立的<see cref="byte"/>数组包
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public ByteBlock WriteBytesPackage(byte[] value, int offset, int length)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Write((byte)1);
|
||||
this.Write(length);
|
||||
this.Write(value, offset, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入一个独立的<see cref="byte"/>数组包
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock WriteBytesPackage(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return this.WriteBytesPackage(value, 0, 0);
|
||||
}
|
||||
return this.WriteBytesPackage(value, 0, value.Length);
|
||||
}
|
||||
|
||||
#endregion BytesPackage
|
||||
|
||||
#region Int32
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="int"/>值
|
||||
/// </summary>
|
||||
public int ReadInt32()
|
||||
{
|
||||
int value = RRQMBitConverter.Default.ToInt32(this._buffer, (int)this.position);
|
||||
this.position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="int"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(int value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Int32
|
||||
|
||||
#region Int16
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="short"/>值
|
||||
/// </summary>
|
||||
public short ReadInt16()
|
||||
{
|
||||
short value = RRQMBitConverter.Default.ToInt16(this._buffer, (int)this.position);
|
||||
this.position += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="short"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(short value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Int16
|
||||
|
||||
#region Int64
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="long"/>值
|
||||
/// </summary>
|
||||
public long ReadInt64()
|
||||
{
|
||||
long value = RRQMBitConverter.Default.ToInt64(this._buffer, (int)this.position);
|
||||
this.position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="long"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(long value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Int64
|
||||
|
||||
#region Boolean
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="bool"/>值
|
||||
/// </summary>
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
bool value = RRQMBitConverter.Default.ToBoolean(this._buffer, (int)this.position);
|
||||
this.position += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="bool"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(bool value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Boolean
|
||||
|
||||
#region Byte
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="byte"/>值
|
||||
/// </summary>
|
||||
public new byte ReadByte()
|
||||
{
|
||||
byte value = this._buffer[this.position];
|
||||
this.position++;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="byte"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public ByteBlock Write(byte value)
|
||||
{
|
||||
this.Write(new byte[] { value }, 0, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Byte
|
||||
|
||||
#region String
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="string"/>值
|
||||
/// </summary>
|
||||
public string ReadString()
|
||||
{
|
||||
byte value = this.ReadByte();
|
||||
if (value == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (value == 1)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort len = this.ReadUInt16();
|
||||
string str = Encoding.UTF8.GetString(this._buffer, (int)this.position, len);
|
||||
this.position += len;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="string"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.Write((byte)0);
|
||||
}
|
||||
else if (value == string.Empty)
|
||||
{
|
||||
this.Write((byte)1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Write((byte)2);
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(value);
|
||||
if (buffer.Length > ushort.MaxValue)
|
||||
{
|
||||
throw new RRQMException("传输长度超长");
|
||||
}
|
||||
this.Write((ushort)buffer.Length);
|
||||
this.Write(buffer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion String
|
||||
|
||||
#region Char
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="char"/>值
|
||||
/// </summary>
|
||||
public char ReadChar()
|
||||
{
|
||||
char value = RRQMBitConverter.Default.ToChar(this._buffer, (int)this.position);
|
||||
this.position += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="char"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(char value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Char
|
||||
|
||||
#region Double
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="double"/>值
|
||||
/// </summary>
|
||||
public double ReadDouble()
|
||||
{
|
||||
double value = RRQMBitConverter.Default.ToDouble(this._buffer, (int)this.position);
|
||||
this.position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="double"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(double value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Double
|
||||
|
||||
#region Float
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="float"/>值
|
||||
/// </summary>
|
||||
public float ReadFloat()
|
||||
{
|
||||
float value = RRQMBitConverter.Default.ToSingle(this._buffer, (int)this.position);
|
||||
this.position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="float"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(float value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Float
|
||||
|
||||
#region UInt16
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="ushort"/>值
|
||||
/// </summary>
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
ushort value = RRQMBitConverter.Default.ToUInt16(this._buffer, (int)this.position);
|
||||
this.position += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="ushort"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(ushort value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion UInt16
|
||||
|
||||
#region UInt32
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="uint"/>值
|
||||
/// </summary>
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
uint value = RRQMBitConverter.Default.ToUInt32(this._buffer, (int)this.position);
|
||||
this.position += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="uint"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(uint value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion UInt32
|
||||
|
||||
#region UInt64
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="ulong"/>值
|
||||
/// </summary>
|
||||
public ulong ReadUInt64()
|
||||
{
|
||||
ulong value = RRQMBitConverter.Default.ToUInt64(this._buffer, (int)this.position);
|
||||
this.position += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="ulong"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(ulong value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion UInt64
|
||||
|
||||
#region DateTime
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个<see cref="DateTime"/>值
|
||||
/// </summary>
|
||||
public DateTime ReadDateTime()
|
||||
{
|
||||
long value = RRQMBitConverter.Default.ToInt64(this._buffer, (int)this.position);
|
||||
this.position += 8;
|
||||
return DateTime.FromBinary(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="DateTime"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public ByteBlock Write(DateTime value)
|
||||
{
|
||||
this.Write(RRQMBitConverter.Default.GetBytes(value.ToBinary()));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion DateTime
|
||||
|
||||
#region Object
|
||||
|
||||
/// <summary>
|
||||
/// 从当前流位置读取一个泛型值
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="serializationType"></param>
|
||||
/// <returns></returns>
|
||||
public T ReadObject<T>(SerializationType serializationType = SerializationType.RRQMBinary)
|
||||
{
|
||||
int length = this.ReadInt32();
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
T obj;
|
||||
|
||||
switch (serializationType)
|
||||
{
|
||||
case SerializationType.RRQMBinary:
|
||||
{
|
||||
obj = SerializeConvert.RRQMBinaryDeserialize<T>(this._buffer, (int)this.position);
|
||||
}
|
||||
break;
|
||||
|
||||
case SerializationType.Json:
|
||||
{
|
||||
string jsonString = Encoding.UTF8.GetString(this._buffer, (int)this.position, length);
|
||||
obj = JsonConvert.DeserializeObject<T>(jsonString);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RRQMException("未定义的序列化类型");
|
||||
}
|
||||
|
||||
this.position += length;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入<see cref="object"/>值
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="serializationType"></param>
|
||||
public ByteBlock WriteObject(object value, SerializationType serializationType = SerializationType.RRQMBinary)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.Write(0);
|
||||
return this;
|
||||
}
|
||||
byte[] data;
|
||||
switch (serializationType)
|
||||
{
|
||||
case SerializationType.RRQMBinary:
|
||||
{
|
||||
data = SerializeConvert.RRQMBinarySerialize(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case SerializationType.Json:
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RRQMException("未定义的序列化类型");
|
||||
}
|
||||
|
||||
this.Write(data.Length);
|
||||
this.Write(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Object
|
||||
}
|
||||
}
|
||||
478
RRQMCore/ByteManager/BytePool.cs
Normal file
478
RRQMCore/ByteManager/BytePool.cs
Normal file
@@ -0,0 +1,478 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace RRQMCore.ByteManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 字节池
|
||||
/// </summary>
|
||||
public static class BytePool
|
||||
{
|
||||
private static ConcurrentDictionary<long, BytesQueue> bytesDictionary = new ConcurrentDictionary<long, BytesQueue>();
|
||||
|
||||
private static bool autoZero;
|
||||
private static long fullSize;
|
||||
private static int keyCapacity;
|
||||
private static int maxBlockSize;
|
||||
private static long maxSize;
|
||||
private static int minBlockSize;
|
||||
|
||||
static BytePool()
|
||||
{
|
||||
keyCapacity = 100;
|
||||
autoZero = false;
|
||||
maxSize = 1024 * 1024 * 512;
|
||||
SetBlockSize(1024, 1024 * 1024 * 20);
|
||||
AddSizeKey(10240);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收内存时,自动归零
|
||||
/// </summary>
|
||||
public static bool AutoZero
|
||||
{
|
||||
get { return autoZero; }
|
||||
set { autoZero = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 键容量
|
||||
/// </summary>
|
||||
public static int KeyCapacity
|
||||
{
|
||||
get { return keyCapacity; }
|
||||
set { keyCapacity = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单个块最大值
|
||||
/// </summary>
|
||||
public static int MaxBlockSize
|
||||
{
|
||||
get { return maxBlockSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 允许的内存池最大值
|
||||
/// </summary>
|
||||
public static long MaxSize
|
||||
{
|
||||
get { return maxSize; }
|
||||
set
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
maxSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单个块最小值
|
||||
/// </summary>
|
||||
public static int MinBlockSize
|
||||
{
|
||||
get { return minBlockSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加尺寸键
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AddSizeKey(int byteSize)
|
||||
{
|
||||
if (bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
bytesDictionary.Clear();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确定是否包含指定尺寸键
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsSizeKey(int byteSize)
|
||||
{
|
||||
return bytesDictionary.ContainsKey(byteSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所以内存键
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long[] GetAllSizeKeys()
|
||||
{
|
||||
return bytesDictionary.Keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取ByteBlock
|
||||
/// </summary>
|
||||
/// <param name="byteSize">长度</param>
|
||||
/// <param name="equalSize">要求长度相同</param>
|
||||
/// <returns></returns>
|
||||
public static ByteBlock GetByteBlock(int byteSize, bool equalSize)
|
||||
{
|
||||
ByteBlock byteBlock = new ByteBlock(GetByteCore(byteSize, equalSize));
|
||||
return byteBlock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取ByteBlock
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <returns></returns>
|
||||
public static ByteBlock GetByteBlock(int byteSize)
|
||||
{
|
||||
if (byteSize < minBlockSize)
|
||||
{
|
||||
byteSize = minBlockSize;
|
||||
}
|
||||
return GetByteBlock(byteSize, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最大长度的ByteBlock
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ByteBlock GetByteBlock()
|
||||
{
|
||||
return GetByteBlock(maxBlockSize, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池容量
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static long GetPoolSize()
|
||||
{
|
||||
long size = 0;
|
||||
foreach (var item in bytesDictionary.Values)
|
||||
{
|
||||
size += item.FullSize;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除尺寸键
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <returns></returns>
|
||||
public static bool RemoveSizeKey(int byteSize)
|
||||
{
|
||||
if (bytesDictionary.TryRemove(byteSize, out BytesQueue queue))
|
||||
{
|
||||
queue.Clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置内存块参数
|
||||
/// </summary>
|
||||
/// <param name="minBlockSize"></param>
|
||||
/// <param name="maxBlockSize"></param>
|
||||
public static void SetBlockSize(int minBlockSize, int maxBlockSize)
|
||||
{
|
||||
BytePool.maxBlockSize = maxBlockSize;
|
||||
BytePool.minBlockSize = minBlockSize;
|
||||
bytesDictionary.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存核心
|
||||
/// </summary>
|
||||
/// <param name="byteSize"></param>
|
||||
/// <param name="equalSize"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] GetByteCore(int byteSize, bool equalSize)
|
||||
{
|
||||
BytesQueue bytesCollection;
|
||||
if (equalSize)
|
||||
{
|
||||
//等长
|
||||
if (bytesDictionary.TryGetValue(byteSize, out bytesCollection))
|
||||
{
|
||||
if (bytesCollection.TryGet(out byte[] bytes))
|
||||
{
|
||||
fullSize -= byteSize;
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckKeyCapacity(byteSize);
|
||||
}
|
||||
return new byte[byteSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
byteSize = HitSize(byteSize);
|
||||
//搜索已创建集合
|
||||
if (bytesDictionary.TryGetValue(byteSize, out bytesCollection))
|
||||
{
|
||||
if (bytesCollection.TryGet(out byte[] bytes))
|
||||
{
|
||||
fullSize -= byteSize;
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckKeyCapacity(byteSize);
|
||||
}
|
||||
return new byte[byteSize];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收内存核心
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
public static void Recycle(byte[] bytes)
|
||||
{
|
||||
if (maxSize > fullSize)
|
||||
{
|
||||
if (bytesDictionary.TryGetValue(bytes.Length, out BytesQueue bytesQueue))
|
||||
{
|
||||
if (autoZero)
|
||||
{
|
||||
Array.Clear(bytes, 0, bytes.Length);
|
||||
}
|
||||
fullSize += bytes.Length;
|
||||
bytesQueue.Add(bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
long size = 0;
|
||||
foreach (var collection in bytesDictionary.Values)
|
||||
{
|
||||
size += collection.FullSize;
|
||||
}
|
||||
fullSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckKeyCapacity(int byteSize)
|
||||
{
|
||||
if (byteSize < minBlockSize || byteSize > maxBlockSize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (bytesDictionary.Count < keyCapacity)
|
||||
{
|
||||
bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
List<BytesQueue> bytesQueues = bytesDictionary.Values.ToList();
|
||||
bytesQueues.Sort((x, y) => { return x.referenced > y.referenced ? -1 : 1; });
|
||||
for (int i = (int)(bytesQueues.Count * 0.2); i < bytesQueues.Count; i++)
|
||||
{
|
||||
if (bytesDictionary.TryRemove(bytesQueues[i].size, out BytesQueue queue))
|
||||
{
|
||||
queue.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int HitSize(int num)
|
||||
{
|
||||
switch (num)
|
||||
{
|
||||
case <= 1024:
|
||||
{
|
||||
return 1024;
|
||||
}
|
||||
case <= 2048:
|
||||
{
|
||||
return 2048;
|
||||
}
|
||||
case <= 4096:
|
||||
{
|
||||
return 4096;
|
||||
}
|
||||
case <= 8192:
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
case <= 10240:
|
||||
{
|
||||
return 10240;
|
||||
}
|
||||
case <= 16384:
|
||||
{
|
||||
return 16384;
|
||||
}
|
||||
case <= 32768:
|
||||
{
|
||||
return 32768;
|
||||
}
|
||||
case <= 65536:
|
||||
{
|
||||
return 65536;
|
||||
}
|
||||
case <= 131072:
|
||||
{
|
||||
return 131072;
|
||||
}
|
||||
case <= 262144:
|
||||
{
|
||||
return 262144;
|
||||
}
|
||||
case <= 524288:
|
||||
{
|
||||
return 524288;
|
||||
}
|
||||
case <= 1048576:
|
||||
{
|
||||
return 1048576;
|
||||
}
|
||||
case <= 2097152:
|
||||
{
|
||||
return 2097152;
|
||||
}
|
||||
case <= 4194304:
|
||||
{
|
||||
return 4194304;
|
||||
}
|
||||
case <= 8388608:
|
||||
{
|
||||
return 8388608;
|
||||
}
|
||||
case <= 16777216:
|
||||
{
|
||||
return 16777216;
|
||||
}
|
||||
case <= 33554432:
|
||||
{
|
||||
return 33554432;
|
||||
}
|
||||
case <= 67108864:
|
||||
{
|
||||
return 67108864;
|
||||
}
|
||||
case <= 134217728:
|
||||
{
|
||||
return 134217728;
|
||||
}
|
||||
default:
|
||||
return num;
|
||||
}
|
||||
|
||||
//U3D无法编译时替换。
|
||||
|
||||
//if (num <= 1024)
|
||||
//{
|
||||
// return 1024;
|
||||
//}
|
||||
//else if (num <= 2048)
|
||||
//{
|
||||
// return 2048;
|
||||
//}
|
||||
//else if (num <= 4096)
|
||||
//{
|
||||
// return 4096;
|
||||
//}
|
||||
//else if (num <= 8192)
|
||||
//{
|
||||
// return 8192;
|
||||
//}
|
||||
//else if (num <= 10240)
|
||||
//{
|
||||
// return 10240;
|
||||
//}
|
||||
//else if (num <= 16384)
|
||||
//{
|
||||
// return 16384;
|
||||
//}
|
||||
//else if (num <= 32768)
|
||||
//{
|
||||
// return 32768;
|
||||
//}
|
||||
//else if (num <= 65536)
|
||||
//{
|
||||
// return 65536;
|
||||
//}
|
||||
//else if (num <= 131072)
|
||||
//{
|
||||
// return 131072;
|
||||
//}
|
||||
//else if (num <= 262144)
|
||||
//{
|
||||
// return 262144;
|
||||
//}
|
||||
//else if (num <= 524288)
|
||||
//{
|
||||
// return 524288;
|
||||
//}
|
||||
//else if (num <= 1048576)
|
||||
//{
|
||||
// return 1048576;
|
||||
//}
|
||||
//else if (num <= 2097152)
|
||||
//{
|
||||
// return 2097152;
|
||||
//}
|
||||
//else if (num <= 4194304)
|
||||
//{
|
||||
// return 4194304;
|
||||
//}
|
||||
//else if (num <= 8388608)
|
||||
//{
|
||||
// return 8388608;
|
||||
//}
|
||||
//else if (num <= 16777216)
|
||||
//{
|
||||
// return 16777216;
|
||||
//}
|
||||
//else if (num <= 33554432)
|
||||
//{
|
||||
// return 33554432;
|
||||
//}
|
||||
//else if (num <= 67108864)
|
||||
//{
|
||||
// return 67108864;
|
||||
//}
|
||||
//else if (num <= 134217728)
|
||||
//{
|
||||
// return 134217728;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// return num;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
RRQMCore/ByteManager/BytesQueue.cs
Normal file
66
RRQMCore/ByteManager/BytesQueue.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RRQMCore.ByteManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 字节块集合
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Count = {bytesQueue.Count}")]
|
||||
internal class BytesQueue
|
||||
{
|
||||
internal int size;
|
||||
|
||||
internal BytesQueue(int size)
|
||||
{
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 占用空间
|
||||
/// </summary>
|
||||
public long FullSize
|
||||
{ get { return this.size * this.bytesQueue.Count; } }
|
||||
|
||||
private ConcurrentQueue<byte[]> bytesQueue = new ConcurrentQueue<byte[]>();
|
||||
|
||||
internal long referenced;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前实例中的空闲的Block
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(out byte[] bytes)
|
||||
{
|
||||
this.referenced++;
|
||||
return this.bytesQueue.TryDequeue(out bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向当前集合添加Block
|
||||
/// </summary>
|
||||
/// <param name="bytes"></param>
|
||||
public void Add(byte[] bytes)
|
||||
{
|
||||
this.bytesQueue.Enqueue(bytes);
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
this.bytesQueue.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
125
RRQMCore/Collections/Concurrent/ConcurrentDoublyDictionary.cs
Normal file
125
RRQMCore/Collections/Concurrent/ConcurrentDoublyDictionary.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace RRQMCore.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// 安全双向字典
|
||||
/// </summary>
|
||||
public class ConcurrentDoublyDictionary<TKey, TValue>
|
||||
{
|
||||
private ConcurrentDictionary<TKey, TValue> keyToValue;
|
||||
private ConcurrentDictionary<TValue, TKey> valueToKey;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ConcurrentDoublyDictionary()
|
||||
{
|
||||
this.keyToValue = new ConcurrentDictionary<TKey, TValue>();
|
||||
this.valueToKey = new ConcurrentDictionary<TValue, TKey>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由键指向值得集合
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<TKey, TValue> KeyToValue => this.keyToValue;
|
||||
|
||||
/// <summary>
|
||||
/// 由值指向键的集合
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<TValue, TKey> ValueToKey => this.valueToKey;
|
||||
|
||||
/// <summary>
|
||||
/// 尝试将指定的键和值添加到字典中。
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
if (this.keyToValue.TryAdd(key, value))
|
||||
{
|
||||
if (this.valueToKey.TryAdd(value, key))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.keyToValue.TryRemove(key, out _);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由键尝试移除
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryRemoveFromKey(TKey key, out TValue value)
|
||||
{
|
||||
if (this.keyToValue.TryRemove(key, out value))
|
||||
{
|
||||
if (this.valueToKey.TryRemove(value, out _))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由值尝试移除
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryRemoveFromValue(TValue value, out TKey key)
|
||||
{
|
||||
if (this.valueToKey.TryRemove(value, out key))
|
||||
{
|
||||
if (this.keyToValue.TryRemove(key, out _))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由键获取到值
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetFromKey(TKey key, out TValue value)
|
||||
{
|
||||
return this.keyToValue.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 由值获取到键
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGetFromValue(TValue value, out TKey key)
|
||||
{
|
||||
return this.valueToKey.TryGetValue(value, out key);
|
||||
}
|
||||
}
|
||||
}
|
||||
870
RRQMCore/Collections/Concurrent/ConcurrentList.cs
Normal file
870
RRQMCore/Collections/Concurrent/ConcurrentList.cs
Normal file
@@ -0,0 +1,870 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// 线程安全的List,其基本操作和List一致。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class ConcurrentList<T> : IList<T>
|
||||
{
|
||||
private readonly List<T> list;
|
||||
[NonSerialized]
|
||||
private readonly ReaderWriterLockSlim locker;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
public ConcurrentList(IEnumerable<T> collection)
|
||||
{
|
||||
this.list = new List<T>(collection);
|
||||
this.locker = new ReaderWriterLockSlim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ConcurrentList()
|
||||
{
|
||||
this.list = new List<T>();
|
||||
this.locker = new ReaderWriterLockSlim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public ConcurrentList(int capacity)
|
||||
{
|
||||
this.list = new List<T>(capacity);
|
||||
this.locker = new ReaderWriterLockSlim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 元素数量
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.Count;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为只读
|
||||
/// </summary>
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取索引元素
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list[index];
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list[index] = value;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加元素
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Add(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Add(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有元素
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Clear();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含某个元素
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.Contains(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制到
|
||||
/// </summary>
|
||||
/// <param name="array"></param>
|
||||
/// <param name="arrayIndex"></param>
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
this.list.CopyTo(array, arrayIndex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
foreach (var item in this.list)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回迭代器组合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 索引
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public int IndexOf(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.IndexOf(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插入
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="item"></param>
|
||||
public void Insert(int index, T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Insert(index, item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除元素
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
return this.list.Remove(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按索引移除
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
if (index < this.list.Count)
|
||||
{
|
||||
this.list.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置容量
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.Capacity;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Capacity = value;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.AddRange(IEnumerable{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
public void AddRange(IEnumerable<T> collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.AddRange(collection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.BinarySearch(T)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public int BinarySearch(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.BinarySearch(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.BinarySearch(T, IComparer{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
public int BinarySearch(T item, IComparer<T> comparer)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.BinarySearch(item, comparer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.BinarySearch(int, int, T, IComparer{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.BinarySearch(index, count, item, comparer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.ConvertAll{TOutput}(Converter{T, TOutput})"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TOutput"></typeparam>
|
||||
/// <param name="converter"></param>
|
||||
/// <returns></returns>
|
||||
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.ConvertAll(converter);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Find(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public T Find(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.Find(match);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindAll(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public List<T> FindAll(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindAll(match);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindIndex(int, int, Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="startIndex"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindIndex(int startIndex, int count, Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindIndex(startIndex, count, match);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindIndex(int, Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="startIndex"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindIndex(int startIndex, Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindIndex(startIndex, match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindIndex(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindIndex(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindIndex(match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindLast(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public T FindLast(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindLast(match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindLastIndex(int, int, Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="startIndex"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindLastIndex(startIndex, count, match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindLastIndex(int, Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="startIndex"></param>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindLastIndex(int startIndex, Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindLastIndex(startIndex, match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.FindLastIndex(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public int FindLastIndex(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.FindLastIndex(match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.ForEach(Action{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public void ForEach(Action<T> action)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
this.list.ForEach(action);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.GetRange(int, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public List<T> GetRange(int index, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.GetRange(index, count);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.IndexOf(T, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public int IndexOf(T item, int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.IndexOf(item, index);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.IndexOf(T, int, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public int IndexOf(T item, int index, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.IndexOf(item, index, count);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.InsertRange(int, IEnumerable{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="collection"></param>
|
||||
public void InsertRange(int index, IEnumerable<T> collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.InsertRange(index, collection);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.LastIndexOf(T)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public int LastIndexOf(T item)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.IndexOf(item);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.LastIndexOf(T, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
public int LastIndexOf(T item, int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.LastIndexOf(item, index);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.LastIndexOf(T, int, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
public int LastIndexOf(T item, int index, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.LastIndexOf(item, index, count);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.RemoveAll(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
public void RemoveAll(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.RemoveAll(match);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.RemoveRange(int, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
public void RemoveRange(int index, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.RemoveRange(index, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Reverse()"/>
|
||||
/// </summary>
|
||||
public void Reverse()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Reverse();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Reverse(int, int)"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
public void Reverse(int index, int count)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Reverse(index, count);
|
||||
}
|
||||
finally { this.locker.ExitWriteLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Sort()"/>
|
||||
/// </summary>
|
||||
public void Sort()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Sort();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Sort(Comparison{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="comparison"></param>
|
||||
public void Sort(Comparison<T> comparison)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Sort(comparison);
|
||||
}
|
||||
finally { this.locker.ExitWriteLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Sort(IComparer{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="comparer"></param>
|
||||
public void Sort(IComparer<T> comparer)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Sort(comparer);
|
||||
}
|
||||
finally { this.locker.ExitWriteLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.Sort(int, int, IComparer{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <param name="comparer"></param>
|
||||
public void Sort(int index, int count, IComparer<T> comparer)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.Sort(index, count, comparer);
|
||||
}
|
||||
finally { this.locker.ExitWriteLock(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.ToArray"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.TrimExcess"/>
|
||||
/// </summary>
|
||||
public void TrimExcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterWriteLock();
|
||||
this.list.TrimExcess();
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="List{T}.TrueForAll(Predicate{T})"/>
|
||||
/// </summary>
|
||||
/// <param name="match"></param>
|
||||
/// <returns></returns>
|
||||
public bool TrueForAll(Predicate<T> match)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.locker.EnterReadLock();
|
||||
return this.list.TrueForAll(match);
|
||||
}
|
||||
finally { this.locker.ExitReadLock(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// 智能安全队列
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class IntelligentConcurrentQueue<T> : ConcurrentQueue<T>
|
||||
{
|
||||
private int count;
|
||||
|
||||
private int maxCount;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="maxCount"></param>
|
||||
public IntelligentConcurrentQueue(int maxCount)
|
||||
{
|
||||
this.maxCount = maxCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 允许的最大长度
|
||||
/// </summary>
|
||||
public int MaxCount
|
||||
{
|
||||
get { return this.maxCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 长度
|
||||
/// </summary>
|
||||
public new int Count
|
||||
{
|
||||
get { return this.count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入队
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public new void Enqueue(T item)
|
||||
{
|
||||
SpinWait.SpinUntil(this.Check);
|
||||
Interlocked.Increment(ref this.count);
|
||||
base.Enqueue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出队
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public new bool TryDequeue(out T result)
|
||||
{
|
||||
if (base.TryDequeue(out result))
|
||||
{
|
||||
Interlocked.Decrement(ref this.count);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Check()
|
||||
{
|
||||
return this.count < this.maxCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
170
RRQMCore/Collections/Concurrent/IntelligentDataQueue.cs
Normal file
170
RRQMCore/Collections/Concurrent/IntelligentDataQueue.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// 智能数据安全队列
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class IntelligentDataQueue<T> : ConcurrentQueue<T> where T : IQueueData
|
||||
{
|
||||
private bool overflowWait;
|
||||
/// <summary>
|
||||
/// 溢出等待
|
||||
/// </summary>
|
||||
public bool OverflowWait
|
||||
{
|
||||
get { return this.overflowWait; }
|
||||
set { this.overflowWait = value; }
|
||||
}
|
||||
|
||||
private Action<bool> onQueueChanged;
|
||||
/// <summary>
|
||||
/// 在队列修改时
|
||||
/// </summary>
|
||||
public Action<bool> OnQueueChanged
|
||||
{
|
||||
get { return this.onQueueChanged; }
|
||||
set { this.onQueueChanged = value; }
|
||||
}
|
||||
|
||||
private bool free;
|
||||
/// <summary>
|
||||
/// 是否有空位允许入队
|
||||
/// </summary>
|
||||
public bool Free
|
||||
{
|
||||
get { return this.free; }
|
||||
}
|
||||
|
||||
private long actualSize;
|
||||
|
||||
private long maxSize;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="maxSize"></param>
|
||||
public IntelligentDataQueue(long maxSize)
|
||||
{
|
||||
this.free = true;
|
||||
this.overflowWait = true;
|
||||
this.MaxSize = maxSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public IntelligentDataQueue() : this(1024 * 1024 * 10)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 允许的最大长度
|
||||
/// </summary>
|
||||
public long MaxSize
|
||||
{
|
||||
get { return this.maxSize; }
|
||||
set
|
||||
{
|
||||
if (value < 1)
|
||||
{
|
||||
value = 1;
|
||||
}
|
||||
this.maxSize = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实际尺寸
|
||||
/// </summary>
|
||||
public long ActualSize
|
||||
{
|
||||
get { return this.actualSize; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空队列
|
||||
/// </summary>
|
||||
public void Clear(Action<T> onClear)
|
||||
{
|
||||
while (base.TryDequeue(out T t))
|
||||
{
|
||||
onClear?.Invoke(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 入队
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public new void Enqueue(T item)
|
||||
{
|
||||
bool free = this.actualSize < this.maxSize;
|
||||
if (this.free != free)
|
||||
{
|
||||
this.free = free;
|
||||
this.onQueueChanged?.Invoke(this.free);
|
||||
}
|
||||
|
||||
if (this.overflowWait)
|
||||
{
|
||||
SpinWait.SpinUntil(this.Check);
|
||||
}
|
||||
|
||||
Interlocked.Add(ref this.actualSize, item.Size);
|
||||
base.Enqueue(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 出队
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
public new bool TryDequeue(out T result)
|
||||
{
|
||||
if (base.TryDequeue(out result))
|
||||
{
|
||||
Interlocked.Add(ref this.actualSize, -result.Size);
|
||||
bool free = this.actualSize < this.maxSize;
|
||||
if (this.free != free)
|
||||
{
|
||||
this.free = free;
|
||||
this.onQueueChanged?.Invoke(this.free);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Check()
|
||||
{
|
||||
return this.actualSize < this.maxSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 队列数据
|
||||
/// </summary>
|
||||
public interface IQueueData
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据长度
|
||||
/// </summary>
|
||||
int Size { get; }
|
||||
}
|
||||
}
|
||||
141
RRQMCore/Common/AppConfigBase.cs
Normal file
141
RRQMCore/Common/AppConfigBase.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行配置类
|
||||
/// </summary>
|
||||
public abstract class AppConfigBase
|
||||
{
|
||||
|
||||
private readonly string fullPath;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="fullPath"></param>
|
||||
public AppConfigBase(string fullPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullPath))
|
||||
{
|
||||
throw new ArgumentException($"“{nameof(fullPath)}”不能为 null 或空。", nameof(fullPath));
|
||||
}
|
||||
|
||||
this.fullPath = fullPath;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置
|
||||
/// </summary>
|
||||
/// <param name="overwrite"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
public bool Save(bool overwrite, out string msg)
|
||||
{
|
||||
if (overwrite == false && File.Exists(this.fullPath))
|
||||
{
|
||||
msg = null;
|
||||
return true;
|
||||
}
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(this.fullPath, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this, Formatting.Indented)));
|
||||
msg = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <returns></returns>
|
||||
public bool Load(out string msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(this.fullPath))
|
||||
{
|
||||
this.Save(false, out _);
|
||||
}
|
||||
var obj = File.ReadAllText(this.fullPath).ToJsonObject(this.GetType());
|
||||
var ps = this.GetType().GetProperties();
|
||||
|
||||
foreach (var item in ps)
|
||||
{
|
||||
item.SetValue(this, item.GetValue(obj));
|
||||
}
|
||||
msg = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认配置。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T GetDefault<T>() where T : AppConfigBase, new()
|
||||
{
|
||||
Type type = typeof(T);
|
||||
if (list.TryGetValue(type, out object value))
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
T _default = ((T)Activator.CreateInstance(typeof(T)));
|
||||
_default.Load(out _);
|
||||
list.Add(type, _default);
|
||||
return _default;
|
||||
}
|
||||
|
||||
static Dictionary<Type, object> list = new Dictionary<Type, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认配置,每次调用该方法时,都会重新加载配置。
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T GetNewDefault<T>() where T : AppConfigBase, new()
|
||||
{
|
||||
T _default = ((T)Activator.CreateInstance(typeof(T)));
|
||||
_default.Load(out _);
|
||||
if (list.ContainsKey(_default.GetType()))
|
||||
{
|
||||
list[_default.GetType()] = _default;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(_default.GetType(), _default);
|
||||
}
|
||||
return _default;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
RRQMCore/Common/Enum/EndianType.cs
Normal file
31
RRQMCore/Common/Enum/EndianType.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 大小端类型
|
||||
/// </summary>
|
||||
public enum EndianType
|
||||
{
|
||||
/// <summary>
|
||||
/// 小端模式
|
||||
/// </summary>
|
||||
Little,
|
||||
|
||||
/// <summary>
|
||||
/// 大端模式
|
||||
/// </summary>
|
||||
Big
|
||||
}
|
||||
}
|
||||
141
RRQMCore/Common/Enum/ResType.cs
Normal file
141
RRQMCore/Common/Enum/ResType.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// RRQM资源枚举
|
||||
/// </summary>
|
||||
public enum ResType
|
||||
{
|
||||
/// <summary>
|
||||
/// 未知知错误
|
||||
/// </summary>
|
||||
UnknownError,
|
||||
|
||||
/// <summary>
|
||||
/// 参数为空
|
||||
/// </summary>
|
||||
ArgumentNull,
|
||||
|
||||
/// <summary>
|
||||
/// 远程终端拒绝该操作
|
||||
/// </summary>
|
||||
RemoteRefuse,
|
||||
|
||||
/// <summary>
|
||||
/// 远程终端不响应该操作
|
||||
/// </summary>
|
||||
RemoteNotSupported,
|
||||
|
||||
/// <summary>
|
||||
/// 远程终端异常
|
||||
/// </summary>
|
||||
RemoteException,
|
||||
|
||||
/// <summary>
|
||||
/// 通道设置失败
|
||||
/// </summary>
|
||||
SetChannelFail,
|
||||
|
||||
/// <summary>
|
||||
/// 路径无效
|
||||
/// </summary>
|
||||
PathInvalid,
|
||||
|
||||
/// <summary>
|
||||
/// 文件已存在
|
||||
/// </summary>
|
||||
FileExists,
|
||||
|
||||
/// <summary>
|
||||
/// 远程文件不存在
|
||||
/// </summary>
|
||||
RemoteFileNotExists,
|
||||
|
||||
/// <summary>
|
||||
/// 创建写入流失败
|
||||
/// </summary>
|
||||
CreateWriteStreamFail,
|
||||
|
||||
/// <summary>
|
||||
/// 没有找到流文件
|
||||
/// </summary>
|
||||
StreamNotFind,
|
||||
|
||||
/// <summary>
|
||||
/// 没有找到客户端
|
||||
/// </summary>
|
||||
ClientNotFind,
|
||||
|
||||
/// <summary>
|
||||
/// 流文件正在被应用
|
||||
/// </summary>
|
||||
StreamReferencing,
|
||||
|
||||
/// <summary>
|
||||
/// 接收流容器为空
|
||||
/// </summary>
|
||||
StreamBucketNull,
|
||||
|
||||
/// <summary>
|
||||
/// 加载流异常。
|
||||
/// </summary>
|
||||
LoadStreamFail,
|
||||
|
||||
/// <summary>
|
||||
/// 事件操作器异常
|
||||
/// </summary>
|
||||
GetEventArgsFail,
|
||||
|
||||
/// <summary>
|
||||
/// 长时间没有响应。
|
||||
/// </summary>
|
||||
NoResponse,
|
||||
|
||||
/// <summary>
|
||||
/// 该Token消息已注册
|
||||
/// </summary>
|
||||
TokenExist,
|
||||
|
||||
/// <summary>
|
||||
/// 信息未找到
|
||||
/// </summary>
|
||||
MessageNotFound,
|
||||
|
||||
/// <summary>
|
||||
/// 内存块已释放
|
||||
/// </summary>
|
||||
ByteBlockDisposed,
|
||||
|
||||
/// <summary>
|
||||
/// 数据处理适配器为空
|
||||
/// </summary>
|
||||
NullDataAdapter,
|
||||
|
||||
/// <summary>
|
||||
/// 操作超时
|
||||
/// </summary>
|
||||
Overtime,
|
||||
|
||||
/// <summary>
|
||||
/// 名称为“{0}”的事件已存在
|
||||
/// </summary>
|
||||
EventExisted,
|
||||
|
||||
/// <summary>
|
||||
/// 名称为“{0}”的事件不存在
|
||||
/// </summary>
|
||||
EventNotExist
|
||||
}
|
||||
}
|
||||
46
RRQMCore/Common/Enum/ResultCode.cs
Normal file
46
RRQMCore/Common/Enum/ResultCode.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 结果类型
|
||||
/// </summary>
|
||||
public enum ResultCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 未执行的
|
||||
/// </summary>
|
||||
Default,
|
||||
|
||||
/// <summary>
|
||||
/// 错误
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
/// <summary>
|
||||
/// 成功
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// 操作超时
|
||||
/// </summary>
|
||||
Overtime,
|
||||
|
||||
/// <summary>
|
||||
/// 操作取消
|
||||
/// </summary>
|
||||
Canceled
|
||||
}
|
||||
}
|
||||
30
RRQMCore/Common/IResult.cs
Normal file
30
RRQMCore/Common/IResult.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回通知接口
|
||||
/// </summary>
|
||||
public interface IResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否成功
|
||||
/// </summary>
|
||||
ResultCode ResultCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
string Message { get; }
|
||||
}
|
||||
}
|
||||
39
RRQMCore/Common/Metadata.cs
Normal file
39
RRQMCore/Common/Metadata.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 可传输的元数据
|
||||
/// </summary>
|
||||
public class Metadata : Dictionary<string, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加或更新
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AddOrUpdate(string key, string value)
|
||||
{
|
||||
if (this.ContainsKey(key))
|
||||
{
|
||||
this[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
436
RRQMCore/Common/RRQMBitConverter.cs
Normal file
436
RRQMCore/Common/RRQMBitConverter.cs
Normal file
@@ -0,0 +1,436 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 将基数据类型转换为指定端的一个字节数组,
|
||||
/// 或将一个字节数组转换为指定端基数据类型。
|
||||
/// </summary>
|
||||
public class RRQMBitConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// 以大端
|
||||
/// </summary>
|
||||
public static RRQMBitConverter BigEndian;
|
||||
|
||||
/// <summary>
|
||||
/// 以小端
|
||||
/// </summary>
|
||||
public static RRQMBitConverter LittleEndian;
|
||||
|
||||
static RRQMBitConverter()
|
||||
{
|
||||
BigEndian = new RRQMBitConverter(EndianType.Big);
|
||||
LittleEndian = new RRQMBitConverter(EndianType.Little);
|
||||
DefaultEndianType = EndianType.Little;
|
||||
}
|
||||
|
||||
private static RRQMBitConverter @default;
|
||||
/// <summary>
|
||||
/// 以默认小端,可通过<see cref="RRQMBitConverter.DefaultEndianType"/>重新指定默认端。
|
||||
/// </summary>
|
||||
public static RRQMBitConverter Default
|
||||
{
|
||||
get { return @default; }
|
||||
}
|
||||
|
||||
private static EndianType @defaultEndianType;
|
||||
/// <summary>
|
||||
/// 默认大小端切换。
|
||||
/// </summary>
|
||||
public static EndianType DefaultEndianType
|
||||
{
|
||||
get { return @defaultEndianType; }
|
||||
set
|
||||
{
|
||||
@defaultEndianType = value;
|
||||
switch (value)
|
||||
{
|
||||
case EndianType.Little:
|
||||
@default = LittleEndian;
|
||||
break;
|
||||
case EndianType.Big:
|
||||
@default = BigEndian;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private EndianType endianType;
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="endianType"></param>
|
||||
public RRQMBitConverter(EndianType endianType)
|
||||
{
|
||||
this.endianType = endianType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定大小端。
|
||||
/// </summary>
|
||||
public EndianType EndianType
|
||||
{
|
||||
get { return this.endianType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前系统是否为设置的大小端
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsSameOfSet()
|
||||
{
|
||||
return !(BitConverter.IsLittleEndian ^ (this.endianType == EndianType.Little));
|
||||
}
|
||||
|
||||
#region ushort
|
||||
/// <summary>
|
||||
/// 转换为指定端2字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(ushort value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的2字节转换为UInt16数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public ushort ToUInt16(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
Array.Copy(buffer, offset, bytes, 0, 2);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToUInt16(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ulong
|
||||
/// <summary>
|
||||
/// 转换为指定端8字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(ulong value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的Ulong数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public ulong ToUInt64(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
Array.Copy(buffer, offset, bytes, 0, 8);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToUInt64(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region bool
|
||||
/// <summary>
|
||||
/// 转换为指定端1字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(bool value)
|
||||
{
|
||||
return BitConverter.GetBytes(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的bool数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public bool ToBoolean(byte[] buffer, int offset)
|
||||
{
|
||||
return BitConverter.ToBoolean(buffer, offset);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region char
|
||||
/// <summary>
|
||||
/// 转换为指定端2字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(char value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的Char数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public char ToChar(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToChar(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region short
|
||||
/// <summary>
|
||||
/// 转换为指定端2字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(short value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的Short数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public short ToInt16(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToInt16(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region int
|
||||
/// <summary>
|
||||
/// 转换为指定端4字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(int value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的int数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public int ToInt32(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToInt32(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
#region long
|
||||
/// <summary>
|
||||
/// 转换为指定端8字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(long value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的long数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public long ToInt64(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToInt64(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
#region uint
|
||||
/// <summary>
|
||||
/// 转换为指定端4字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(uint value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的Uint数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public uint ToUInt32(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToUInt32(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region float
|
||||
/// <summary>
|
||||
/// 转换为指定端4字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(float value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的float数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public float ToSingle(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[4];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region long
|
||||
/// <summary>
|
||||
/// 转换为指定端8字节
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetBytes(double value)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为指定端模式的double数据。
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public double ToDouble(byte[] buffer, int offset)
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
Array.Copy(buffer, offset, bytes, 0, bytes.Length);
|
||||
if (!this.IsSameOfSet())
|
||||
{
|
||||
Array.Reverse(bytes);
|
||||
}
|
||||
return BitConverter.ToDouble(bytes, 0);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
40
RRQMCore/Common/RRQMCoreTools.cs
Normal file
40
RRQMCore/Common/RRQMCoreTools.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// RRQMCoreTools
|
||||
/// </summary>
|
||||
public static class RRQMCoreTools
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断字符串compare 在 input字符串中出现的次数
|
||||
/// </summary>
|
||||
/// <param name="input">源字符串</param>
|
||||
/// <param name="compare">用于比较的字符串</param>
|
||||
/// <returns>字符串compare 在 input字符串中出现的次数</returns>
|
||||
public static int GetStringCount(string input, string compare)
|
||||
{
|
||||
int index = input.IndexOf(compare);
|
||||
if (index != -1)
|
||||
{
|
||||
return 1 + GetStringCount(input.Substring(index + compare.Length), compare);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
RRQMCore/Common/RRQMReadonly.cs
Normal file
45
RRQMCore/Common/RRQMReadonly.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 常量
|
||||
/// </summary>
|
||||
public class RRQMReadonly
|
||||
{
|
||||
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
|
||||
public static readonly Type stringType = typeof(string);
|
||||
public static readonly Type byteType = typeof(byte);
|
||||
public static readonly Type sbyteType = typeof(sbyte);
|
||||
public static readonly Type shortType = typeof(short);
|
||||
public static readonly Type ushortType = typeof(ushort);
|
||||
public static readonly Type intType = typeof(int);
|
||||
public static readonly Type uintType = typeof(uint);
|
||||
public static readonly Type boolType = typeof(bool);
|
||||
public static readonly Type charType = typeof(char);
|
||||
public static readonly Type longType = typeof(long);
|
||||
public static readonly Type ulongType = typeof(ulong);
|
||||
public static readonly Type floatType = typeof(float);
|
||||
public static readonly Type doubleType = typeof(double);
|
||||
public static readonly Type decimalType = typeof(decimal);
|
||||
public static readonly Type dateTimeType = typeof(DateTime);
|
||||
public static readonly Type bytesType = typeof(byte[]);
|
||||
public static readonly Type dicType = typeof(IDictionary);
|
||||
public static readonly Type iEnumerableType = typeof(IEnumerable);
|
||||
public static readonly Type listType = typeof(IList);
|
||||
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
|
||||
}
|
||||
}
|
||||
61
RRQMCore/Common/Result.cs
Normal file
61
RRQMCore/Common/Result.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 结果返回
|
||||
/// </summary>
|
||||
public struct Result : IResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="resultCode"></param>
|
||||
/// <param name="message"></param>
|
||||
public Result(ResultCode resultCode, string message)
|
||||
{
|
||||
this.ResultCode = resultCode;
|
||||
this.Message = message;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="resultCode"></param>
|
||||
public Result(ResultCode resultCode)
|
||||
{
|
||||
this.ResultCode = resultCode;
|
||||
this.Message = resultCode.GetResString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public ResultCode ResultCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
public string Message { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// ToString
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"类型:{this.ResultCode},信息:{this.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
113
RRQMCore/Common/SnowflakeIDGenerator.cs
Normal file
113
RRQMCore/Common/SnowflakeIDGenerator.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪花ID生成器(该代码来自网络)
|
||||
/// </summary>
|
||||
public class SnowflakeIDGenerator
|
||||
{
|
||||
//机器ID
|
||||
private static long workerId;
|
||||
|
||||
private static long twepoch = 687888001020L; //唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
|
||||
private static long sequence = 0L;
|
||||
private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)
|
||||
|
||||
/// <summary>
|
||||
/// 最大机器ID
|
||||
/// </summary>
|
||||
public static long maxWorkerId = -1L ^ (-1L << workerIdBits); //最大机器ID
|
||||
|
||||
private static int sequenceBits = 10; //计数器字节数,10个字节用来保存计数码
|
||||
private static int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
|
||||
private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
|
||||
|
||||
/// <summary>
|
||||
/// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
|
||||
/// </summary>
|
||||
public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
|
||||
|
||||
private long lastTimestamp = -1L;
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
/// <param name="workerId"></param>
|
||||
public SnowflakeIDGenerator(long workerId)
|
||||
{
|
||||
if (workerId > maxWorkerId || workerId < 0)
|
||||
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", workerId));
|
||||
SnowflakeIDGenerator.workerId = workerId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取ID
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public long NextID()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
long timestamp = this.timeGen();
|
||||
if (this.lastTimestamp == timestamp)
|
||||
{ //同一微妙中生成ID
|
||||
SnowflakeIDGenerator.sequence = (SnowflakeIDGenerator.sequence + 1) & SnowflakeIDGenerator.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
|
||||
if (SnowflakeIDGenerator.sequence == 0)
|
||||
{
|
||||
//一微妙内产生的ID计数已达上限,等待下一微妙
|
||||
timestamp = this.tillNextMillis(this.lastTimestamp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //不同微秒生成ID
|
||||
SnowflakeIDGenerator.sequence = 0; //计数清0
|
||||
}
|
||||
if (timestamp < this.lastTimestamp)
|
||||
{ //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
|
||||
throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds",
|
||||
this.lastTimestamp - timestamp));
|
||||
}
|
||||
this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
|
||||
long nextId = (timestamp - twepoch << timestampLeftShift) | SnowflakeIDGenerator.workerId << SnowflakeIDGenerator.workerIdShift | SnowflakeIDGenerator.sequence;
|
||||
return nextId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下一微秒时间戳
|
||||
/// </summary>
|
||||
/// <param name="lastTimestamp"></param>
|
||||
/// <returns></returns>
|
||||
private long tillNextMillis(long lastTimestamp)
|
||||
{
|
||||
long timestamp = this.timeGen();
|
||||
while (timestamp <= lastTimestamp)
|
||||
{
|
||||
timestamp = this.timeGen();
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成当前时间戳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private long timeGen()
|
||||
{
|
||||
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
RRQMCore/Common/StringResStore.cs
Normal file
54
RRQMCore/Common/StringResStore.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 字符串资源字典
|
||||
/// </summary>
|
||||
public static class StringResStore
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取资源字符
|
||||
/// </summary>
|
||||
/// <param name="enum"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetResString(this Enum @enum)
|
||||
{
|
||||
string res = Resource.ResourceManager.GetString(@enum.ToString());
|
||||
if (res == null)
|
||||
{
|
||||
return @enum.ToString();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源字符
|
||||
/// </summary>
|
||||
/// <param name="enum"></param>
|
||||
/// <param name="objs"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetResString(this Enum @enum, params object[] objs)
|
||||
{
|
||||
string res = Resource.ResourceManager.GetString(@enum.ToString());
|
||||
if (res == null)
|
||||
{
|
||||
return @enum.ToString();
|
||||
}
|
||||
return res.Format(objs);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
RRQMCore/Data/Converter/CollectionConvert.cs
Normal file
22
RRQMCore/Data/Converter/CollectionConvert.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Data.Converter
|
||||
{
|
||||
/// <summary>
|
||||
/// 集合转换器
|
||||
/// </summary>
|
||||
public class CollectionConvert
|
||||
{
|
||||
}
|
||||
}
|
||||
91
RRQMCore/Data/Converter/ValueConvert.cs
Normal file
91
RRQMCore/Data/Converter/ValueConvert.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Data.Converter
|
||||
{
|
||||
/// <summary>
|
||||
/// 值转换器
|
||||
/// </summary>
|
||||
public static class ValueConvert
|
||||
{
|
||||
/// <summary>
|
||||
/// int型转换器
|
||||
/// </summary>
|
||||
/// <param name="valueString">数字字符串</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>返回值结果</returns>
|
||||
public static int IntConvert(string valueString, int defaultValue = 0)
|
||||
{
|
||||
int result;
|
||||
if (int.TryParse(valueString, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// int型转换器
|
||||
/// </summary>
|
||||
/// <param name="valueObject"></param>
|
||||
/// <returns></returns>
|
||||
public static int IntConvert(object valueObject)
|
||||
{
|
||||
return (int)valueObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// long值转换器
|
||||
/// </summary>
|
||||
/// <param name="valueObject"></param>
|
||||
/// <returns></returns>
|
||||
public static long LongConvert(object valueObject)
|
||||
{
|
||||
return (long)valueObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 双精度值转换
|
||||
/// </summary>
|
||||
/// <param name="valueString">数字字符串</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>返回值结果</returns>
|
||||
public static double DoubleConvert(string valueString, double defaultValue = 0)
|
||||
{
|
||||
double result;
|
||||
if (double.TryParse(valueString, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 枚举类型转换
|
||||
/// </summary>
|
||||
/// <typeparam name="T">枚举类型</typeparam>
|
||||
/// <param name="valueString">枚举字符串</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>返回值结果</returns>
|
||||
public static T EnumConvert<T>(string valueString, T defaultValue = default(T)) where T : struct
|
||||
{
|
||||
T result;
|
||||
if (Enum.TryParse(valueString, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
RRQMCore/Data/Security/DataLock.cs
Normal file
69
RRQMCore/Data/Security/DataLock.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.Data.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据锁,用于加密或解密
|
||||
/// </summary>
|
||||
public static class DataLock
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用3DES加密
|
||||
/// </summary>
|
||||
/// <param name="data">待加密字节</param>
|
||||
/// <param name="encryptKey">加密口令(长度为8)</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] EncryptDES(byte[] data, string encryptKey)
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
|
||||
byte[] rgbIV = { 0x12, 0x34, 4, 0x78, 0x90, 255, 0xCD, 0xEF };
|
||||
DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
cStream.Write(data, 0, data.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return mStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用3DES解密
|
||||
/// </summary>
|
||||
/// <param name="data">待解密字节</param>
|
||||
/// <param name="decryptionKey">解密口令(长度为8)</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] DecryptDES(byte[] data, string decryptionKey)
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptionKey);
|
||||
byte[] rgbIV = { 0x12, 0x34, 4, 0x78, 0x90, 255, 0xCD, 0xEF };
|
||||
DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
|
||||
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
cStream.Write(data, 0, data.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return mStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
721
RRQMCore/Data/XML/XmlTool.cs
Normal file
721
RRQMCore/Data/XML/XmlTool.cs
Normal file
@@ -0,0 +1,721 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace RRQMCore.Data.XML
|
||||
{
|
||||
/// <summary>
|
||||
/// xml主类
|
||||
/// </summary>
|
||||
public class XmlTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="path">文件路径,包含文件名</param>
|
||||
public XmlTool(string path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
private string path = null;
|
||||
|
||||
#region 存储
|
||||
|
||||
/// <summary>
|
||||
/// 单节点,单属性储存
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Attribute_name">属性名</param>
|
||||
/// <param name="Attribute_value">属性值</param>
|
||||
public void AttributeStorage(string NodeName, string Attribute_name, string Attribute_value)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{//存在Xml的文件
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
bool N = false;//节点判断变量
|
||||
foreach (XmlNode item in nodeList)
|
||||
{//判断是否存在该节点
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
N = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (N == false)
|
||||
{//不存在节点,属性,建立节点,属性
|
||||
XmlElement PointName = xml.CreateElement(NodeName);
|
||||
PointName.SetAttribute(Attribute_name, Attribute_value);
|
||||
root.AppendChild(PointName);
|
||||
}
|
||||
else
|
||||
{//存在属性进行赋值
|
||||
XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName);
|
||||
PointName.Attributes[Attribute_name].Value = Attribute_value;
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
XmlElement root = xml.CreateElement("Root");
|
||||
xml.AppendChild(root);//根元素
|
||||
|
||||
XmlElement PointName = xml.CreateElement(NodeName);
|
||||
PointName.SetAttribute(Attribute_name, Attribute_value);
|
||||
root.AppendChild(PointName);
|
||||
xml.Save(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单节点,多属性存储
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Attribute_name">属性集合</param>
|
||||
/// <param name="Attribute_value">属性值集合</param>
|
||||
public void AttributeStorage(string NodeName, string[] Attribute_name, string[] Attribute_value)
|
||||
{
|
||||
if (Attribute_name.Length != Attribute_value.Length)
|
||||
{
|
||||
Console.WriteLine("属性名数量和属性值数量不一致,无法储存");
|
||||
return;
|
||||
}
|
||||
if (File.Exists(this.path))
|
||||
{//存在Xml的文件
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
bool N = false;//节点变量
|
||||
foreach (XmlNode item in nodeList)
|
||||
{//判断是否存在该节点
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
N = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (N == false)
|
||||
{//不存在节点,属性,建立节点,属性
|
||||
XmlElement PointName = xml.CreateElement(NodeName);
|
||||
for (int i = 0; i < Attribute_name.Length; i++)
|
||||
{
|
||||
PointName.SetAttribute(Attribute_name[i], Attribute_value[i]);
|
||||
root.AppendChild(PointName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{//存在属性进行赋值
|
||||
XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName);
|
||||
for (int i = 0; i < Attribute_name.Length; i++)
|
||||
{
|
||||
PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i];
|
||||
}
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
XmlElement root = xml.CreateElement("Root");
|
||||
xml.AppendChild(root);//根元素
|
||||
|
||||
XmlElement PointName = xml.CreateElement(NodeName);
|
||||
for (int i = 0; i < Attribute_name.Length; i++)
|
||||
{
|
||||
PointName.SetAttribute(Attribute_name[i], Attribute_value[i]);
|
||||
root.AppendChild(PointName);
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单节点,单属性多集合存储
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点集合</param>
|
||||
/// <param name="Attribute_name">属性名集合</param>
|
||||
/// <param name="Attribute_value">属性值集合</param>
|
||||
public void AttributeStorage(string[] NodeName, string[] Attribute_name, string[] Attribute_value)
|
||||
{
|
||||
if ((Attribute_name.Length != Attribute_value.Length) && NodeName.Length != Attribute_name.Length)
|
||||
{
|
||||
Console.WriteLine("属性名数量和属性值数量不一致,无法储存");
|
||||
return;
|
||||
}
|
||||
if (File.Exists(this.path))
|
||||
{//存在Xml的文件
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
for (int i = 0; i < NodeName.Length; i++)
|
||||
{
|
||||
bool N = false;//节点变量
|
||||
foreach (XmlNode item in nodeList)
|
||||
{//判断是否存在该节点
|
||||
if (item.Name == NodeName[i])
|
||||
{
|
||||
N = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (N == false)
|
||||
{//不存在节点,属性,建立节点,属性
|
||||
XmlElement PointName = xml.CreateElement(NodeName[i]);
|
||||
|
||||
PointName.SetAttribute(Attribute_name[i], Attribute_value[i]);
|
||||
root.AppendChild(PointName);
|
||||
}
|
||||
else
|
||||
{//存在属性进行赋值
|
||||
XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName);
|
||||
|
||||
PointName.Attributes[Attribute_name[i]].Value = Attribute_value[i];
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
XmlElement root = xml.CreateElement("Root");
|
||||
xml.AppendChild(root);//根元素
|
||||
for (int i = 0; i < NodeName.Length; i++)
|
||||
{
|
||||
XmlElement PointName = xml.CreateElement(NodeName[i]);
|
||||
PointName.SetAttribute(Attribute_name[i], Attribute_value[i]);
|
||||
root.AppendChild(PointName);
|
||||
|
||||
xml.Save(this.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多节点,多属性,多集合存储
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点集合</param>
|
||||
/// <param name="Attribute_name">属性集合</param>
|
||||
/// <param name="AttributeNumber">每个节点的属性数量</param>
|
||||
/// <param name="Attribute_value">属性值集合</param>
|
||||
public void AttributeStorage(string[] NodeName, string[] Attribute_name, int AttributeNumber, params string[][] Attribute_value)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
//存在Xml的文件
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
for (int i = 0; i < NodeName.Length; i++)
|
||||
{
|
||||
bool N = false;//节点变量
|
||||
foreach (XmlNode item in nodeList)
|
||||
{//判断是否存在该节点
|
||||
if (item.Name == NodeName[i])
|
||||
{
|
||||
N = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (N == false)
|
||||
{//不存在节点,属性,建立节点,属性
|
||||
XmlElement PointName = xml.CreateElement(NodeName[i]);
|
||||
for (int j = 0; j < AttributeNumber; j++)
|
||||
{
|
||||
PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]);
|
||||
}
|
||||
|
||||
root.AppendChild(PointName);
|
||||
}
|
||||
else
|
||||
{//存在属性进行赋值
|
||||
XmlNode PointName = xml.SelectSingleNode("Root/" + NodeName[i]);
|
||||
|
||||
for (int j = 0; j < AttributeNumber; j++)
|
||||
{
|
||||
PointName.Attributes[Attribute_name[j]].Value = Attribute_value[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
XmlDeclaration dec = xml.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
XmlElement root = xml.CreateElement("Root");
|
||||
xml.AppendChild(root);//根元素
|
||||
for (int i = 0; i < NodeName.Length; i++)
|
||||
{
|
||||
XmlElement PointName = xml.CreateElement(NodeName[i]);
|
||||
for (int j = 0; j < AttributeNumber; j++)
|
||||
{
|
||||
PointName.SetAttribute(Attribute_name[j], Attribute_value[j][i]);
|
||||
}
|
||||
root.AppendChild(PointName);
|
||||
|
||||
xml.Save(this.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点值存储
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Text">文本</param>
|
||||
public void NodeStorage(string NodeName, string Text)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
bool n = false;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
item.InnerText = Text;
|
||||
n = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == false)
|
||||
{
|
||||
XmlElement other = xml.CreateElement(NodeName);
|
||||
other.InnerText = Text;
|
||||
root.AppendChild(other);
|
||||
}
|
||||
xml.Save(this.path);
|
||||
}
|
||||
else
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
|
||||
XmlElement Root = doc.CreateElement("Root");
|
||||
doc.AppendChild(Root);//根元素
|
||||
|
||||
XmlElement Node = doc.CreateElement(NodeName);
|
||||
Node.InnerText = Text;
|
||||
Root.AppendChild(Node);
|
||||
|
||||
doc.Save(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 存储
|
||||
|
||||
#region
|
||||
|
||||
/// <summary>
|
||||
/// 通过节点取值
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <returns>取值失败返回null</returns>
|
||||
public string SearchNode(string NodeName)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
return item.InnerText;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找数字
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Attribute_name">属性名</param>
|
||||
/// <returns>取值失败返回0</returns>
|
||||
public int SearchNumber(string NodeName, string Attribute_name)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
if (item.Attributes[Attribute_name] != null)
|
||||
{
|
||||
return Convert.ToInt32(item.Attributes[Attribute_name].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找属性值
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Attribute_name">属性名</param>
|
||||
/// <returns>取值失败返回null</returns>
|
||||
public string SearchWords(string NodeName, string Attribute_name)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
if (item.Attributes[Attribute_name] != null)
|
||||
{
|
||||
return item.Attributes[Attribute_name].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找布尔值
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <param name="Attribute_name">属性值</param>
|
||||
/// <returns>返回查找结果,查询失败返回false</returns>
|
||||
public bool SearchBoolean(string NodeName, string Attribute_name)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
if (item.Attributes[Attribute_name] != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToBoolean(item.Attributes[Attribute_name].Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找属性值集合
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名集合</param>
|
||||
/// <param name="Attribute_name">属性名集合</param>
|
||||
/// <returns>文件不在返回null,单个属性不在返回“空”</returns>
|
||||
public string[] SearchWords(string[] NodeName, string[] Attribute_name)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
string[] s = new string[NodeName.Length];
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
for (int i = 0; i < NodeName.Length; i++)
|
||||
{
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName[i])
|
||||
{
|
||||
if (item.Attributes[Attribute_name[i]] != null)
|
||||
{
|
||||
s[i] = item.Attributes[Attribute_name[i]].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
s[i] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过确切属性值,属性名,查找其他属性值
|
||||
/// </summary>
|
||||
/// <param name="Attribute_name1">已知属性名</param>
|
||||
/// <param name="Attribute_value">已知属性值</param>
|
||||
/// <param name="Attribute_name2">待查属性名</param>
|
||||
/// <returns>待查属性值</returns>
|
||||
public string[] SearchWords(string Attribute_name1, string Attribute_value, string Attribute_name2)
|
||||
{
|
||||
List<string> values = new List<string>();
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Attributes[Attribute_name1] != null)
|
||||
{
|
||||
if (item.Attributes[Attribute_name1].Value == Attribute_value)
|
||||
{
|
||||
if (item.Attributes[Attribute_name2] != null)
|
||||
{
|
||||
values.Add(item.Attributes[Attribute_name2].Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return values.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找节点的所有属性值
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点 名</param>
|
||||
/// <returns>返回查找键值对,查询失败返回null</returns>
|
||||
public Dictionary<string, string> SearchAllAttributes(string NodeName)
|
||||
{
|
||||
Dictionary<string, string> Attributes = new Dictionary<string, string>();
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
XmlAttributeCollection attributeCollection = item.Attributes;
|
||||
if (attributeCollection != null)
|
||||
{
|
||||
foreach (XmlAttribute attribute in attributeCollection)
|
||||
{
|
||||
Attributes.Add(attribute.Name, attribute.Value);
|
||||
}
|
||||
}
|
||||
return Attributes;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过确切属性值,属性名,查找其他属性的布尔值
|
||||
/// </summary>
|
||||
/// <param name="Attribute_name1">已知属性名</param>
|
||||
/// <param name="Attribute_value">已知属性值</param>
|
||||
/// <param name="Attribute_name2">待查属性名</param>
|
||||
/// <returns>待查布尔值,失败返回false</returns>
|
||||
public bool SearchBoolean(string Attribute_name1, string Attribute_value, string Attribute_name2)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Attributes[Attribute_name1].Value == Attribute_value)
|
||||
{
|
||||
if (item.Attributes[Attribute_name2] != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToBoolean(item.Attributes[Attribute_name2].Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 按节点名移除节点
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <returns>是否移除成功</returns>
|
||||
public bool RemoveNode(string NodeName)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
root.RemoveChild(item);
|
||||
xml.Save(this.path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按确切的属性名,属性值删除节点
|
||||
/// </summary>
|
||||
/// <param name="Attribute_name">属性名</param>
|
||||
/// <param name="Attribute_value">属性值</param>
|
||||
/// <returns>是否移除成功</returns>
|
||||
public bool RemoveNode(string Attribute_name, string Attribute_value)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Attributes[Attribute_name] != null)
|
||||
{
|
||||
if (item.Attributes[Attribute_name].Value == Attribute_value)
|
||||
{
|
||||
root.RemoveChild(item);
|
||||
xml.Save(this.path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 如果节点中有日期属性,把日期之前的节点都删除
|
||||
/// </summary>
|
||||
/// <param name="Attribute_name">属性名</param>
|
||||
/// <param name="dateTime">截止时间</param>
|
||||
/// <returns>是否删除成功</returns>
|
||||
public bool RemoveNode(string Attribute_name, DateTime dateTime)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
for (int i = 0; i < nodeList.Count; i++)
|
||||
{
|
||||
if (nodeList[i].Attributes[Attribute_name] != null)
|
||||
{
|
||||
DateTime dt = Convert.ToDateTime(nodeList[i].Attributes[Attribute_name].Value);
|
||||
if (DateTime.Compare(dt, dateTime) < 0)
|
||||
{
|
||||
root.RemoveChild(nodeList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
xml.Save(this.path);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断节点是否存在
|
||||
/// </summary>
|
||||
/// <param name="NodeName">节点名</param>
|
||||
/// <returns>返回结果</returns>
|
||||
public bool NodeExist(string NodeName)
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
XmlNodeList nodeList = root.ChildNodes;
|
||||
foreach (XmlNode item in nodeList)
|
||||
{
|
||||
if (item.Name == NodeName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有节点,不包含子节点
|
||||
/// </summary>
|
||||
/// <returns>返回删除是否成功</returns>
|
||||
public bool RemoveAllNode()
|
||||
{
|
||||
if (File.Exists(this.path))
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(this.path);
|
||||
XmlElement root = xml.DocumentElement;
|
||||
root.RemoveAll();
|
||||
xml.Save(this.path);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
RRQMCore/Dependency/Attribute/DataValidationAttribute.cs
Normal file
24
RRQMCore/Dependency/Attribute/DataValidationAttribute.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Dependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 依赖属性数据验证
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class DataValidationAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
108
RRQMCore/Dependency/DependencyProperty.cs
Normal file
108
RRQMCore/Dependency/DependencyProperty.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMCore.Dependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 依赖项属性
|
||||
/// </summary>
|
||||
public class DependencyProperty
|
||||
{
|
||||
private DependencyProperty()
|
||||
{
|
||||
}
|
||||
|
||||
private string name;
|
||||
|
||||
/// <summary>
|
||||
/// 属性名
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return this.name; }
|
||||
}
|
||||
|
||||
private Type owner;
|
||||
|
||||
/// <summary>
|
||||
/// 所属类型
|
||||
/// </summary>
|
||||
public Type Owner
|
||||
{
|
||||
get { return this.owner; }
|
||||
}
|
||||
|
||||
private Type valueType;
|
||||
|
||||
/// <summary>
|
||||
/// 值类型
|
||||
/// </summary>
|
||||
public Type ValueType
|
||||
{
|
||||
get { return this.valueType; }
|
||||
}
|
||||
|
||||
private object value;
|
||||
|
||||
/// <summary>
|
||||
/// 默认值
|
||||
/// </summary>
|
||||
public object DefauleValue
|
||||
{
|
||||
get { return this.value; }
|
||||
}
|
||||
|
||||
internal void DataValidation(object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
if (typeof(ValueType).IsAssignableFrom(this.valueType))
|
||||
{
|
||||
throw new RRQMException($"属性“{this.name}”赋值类型不允许出现Null");
|
||||
}
|
||||
}
|
||||
else if (!this.valueType.IsAssignableFrom(value.GetType()))
|
||||
{
|
||||
throw new RRQMException($"属性“{this.name}”赋值类型与注册类型不一致,应当注入“{this.valueType}”类型");
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetDefauleValue(object value)
|
||||
{
|
||||
this.DataValidation(value);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册依赖项属性
|
||||
/// </summary>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="valueType"></param>
|
||||
/// <param name="owner"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static DependencyProperty Register(string propertyName, Type valueType, Type owner, object value)
|
||||
{
|
||||
FieldInfo fieldInfo = owner.GetField($"{propertyName}Property");
|
||||
DependencyProperty dp = new DependencyProperty();
|
||||
dp.name = propertyName;
|
||||
dp.valueType = valueType;
|
||||
dp.owner = owner;
|
||||
dp.SetDefauleValue(value);
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
RRQMCore/Dependency/RRQMDependencyObject.cs
Normal file
76
RRQMCore/Dependency/RRQMDependencyObject.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace RRQMCore.Dependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 依赖项对象
|
||||
/// </summary>
|
||||
public class RRQMDependencyObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMDependencyObject()
|
||||
{
|
||||
this.dp = new ConcurrentDictionary<DependencyProperty, object>();
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
|
||||
private ConcurrentDictionary<DependencyProperty, object> dp;
|
||||
|
||||
/// <summary>
|
||||
/// 获取值
|
||||
/// </summary>
|
||||
/// <param name="dependencyProperty"></param>
|
||||
/// <returns></returns>
|
||||
public object GetValue(DependencyProperty dependencyProperty)
|
||||
{
|
||||
if (this.dp.TryGetValue(dependencyProperty, out object value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dependencyProperty.DefauleValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取值
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="dependencyProperty"></param>
|
||||
/// <returns></returns>
|
||||
public T GetValue<T>(DependencyProperty dependencyProperty)
|
||||
{
|
||||
return (T)this.GetValue(dependencyProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置值
|
||||
/// </summary>
|
||||
/// <param name="dependencyProperty"></param>
|
||||
/// <param name="value"></param>
|
||||
public RRQMDependencyObject SetValue(DependencyProperty dependencyProperty, object value)
|
||||
{
|
||||
dependencyProperty.DataValidation(value);
|
||||
this.dp.AddOrUpdate(dependencyProperty, value, (DependencyProperty dp, object v) =>
|
||||
{
|
||||
return value;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
RRQMCore/Diagnostics/TimeMeasurer.cs
Normal file
48
RRQMCore/Diagnostics/TimeMeasurer.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMCore.Diagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// 时间测量器
|
||||
/// </summary>
|
||||
public class TimeMeasurer
|
||||
{
|
||||
/// <summary>
|
||||
/// 开始运行
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public static TimeSpan Run(Action action)
|
||||
{
|
||||
Stopwatch stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
action?.Invoke();
|
||||
stopwatch.Stop();
|
||||
return stopwatch.Elapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步执行
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<TimeSpan> RunAsync(Action action)
|
||||
{
|
||||
return Task.Run(() => { return Run(action); });
|
||||
}
|
||||
}
|
||||
}
|
||||
24
RRQMCore/Event/RRQMEventAgrs.cs
Normal file
24
RRQMCore/Event/RRQMEventAgrs.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 若汝棋茗所有事件基类
|
||||
/// </summary>
|
||||
public class RRQMEventArgs : EventArgs
|
||||
{
|
||||
}
|
||||
}
|
||||
121
RRQMCore/Exceptions/RRQMCoreExceptions.cs
Normal file
121
RRQMCore/Exceptions/RRQMCoreExceptions.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore
|
||||
{
|
||||
/// <summary>
|
||||
/// 若汝棋茗程序集异常类基类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RRQMException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMException() : base()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMException(ResType resType, params object[] fms) : base(resType.GetResString(fms)) { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息已注册
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MessageRegisteredException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="mes"></param>
|
||||
public MessageRegisteredException(string mes) : base(mes)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 未找到消息异常类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MessageNotFoundException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///构造函数
|
||||
/// </summary>
|
||||
/// <param name="mes"></param>
|
||||
public MessageNotFoundException(string mes) : base(mes)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内存块已释放
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ByteBlockDisposedException : RRQMException
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ByteBlockDisposedException() { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public ByteBlockDisposedException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public ByteBlockDisposedException(string message, Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected ByteBlockDisposedException(
|
||||
System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
558
RRQMCore/Helper/RRQMCoreHelper.cs
Normal file
558
RRQMCore/Helper/RRQMCoreHelper.cs
Normal file
@@ -0,0 +1,558 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Log;
|
||||
using RRQMCore.XREF.Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RRQMCore.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// 辅助扩展类
|
||||
/// </summary>
|
||||
public static class RRQMCoreHelper
|
||||
{
|
||||
|
||||
#region 日志
|
||||
/// <summary>
|
||||
/// 输出消息日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Message(this ILog logger, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Message, null, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出警示日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Warning(this ILog logger, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Warning, null, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出错误日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Error(this ILog logger, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Error, null, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出异常日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="ex"></param>
|
||||
public static void Exception(this ILog logger, Exception ex)
|
||||
{
|
||||
logger.Debug(LogType.Error, null, ex.Message, ex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出消息日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Message(this ILog logger, object source, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Message, source, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出警示日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Warning(this ILog logger, object source, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Warning, source, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出错误日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="msg"></param>
|
||||
public static void Error(this ILog logger, object source, string msg)
|
||||
{
|
||||
logger.Debug(LogType.Error, source, msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出异常日志
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="ex"></param>
|
||||
public static void Exception(this ILog logger, object source, Exception ex)
|
||||
{
|
||||
logger.Debug(LogType.Error, source, ex.Message, ex);
|
||||
}
|
||||
#endregion 日志
|
||||
|
||||
/// <summary>
|
||||
/// 索引包含数组
|
||||
/// </summary>
|
||||
/// <param name="srcByteArray"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="subByteArray"></param>
|
||||
/// <returns></returns>
|
||||
public static List<int> IndexOfInclude(this byte[] srcByteArray, int offset, int length, byte[] subByteArray)
|
||||
{
|
||||
int subByteArrayLen = subByteArray.Length;
|
||||
List<int> indexes = new List<int>();
|
||||
if (length < subByteArrayLen)
|
||||
{
|
||||
return indexes;
|
||||
}
|
||||
int hitLength = 0;
|
||||
for (int i = offset; i < length; i++)
|
||||
{
|
||||
if (srcByteArray[i] == subByteArray[hitLength])
|
||||
{
|
||||
hitLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitLength = 0;
|
||||
}
|
||||
|
||||
if (hitLength == subByteArray.Length)
|
||||
{
|
||||
hitLength = 0;
|
||||
indexes.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 索引第一个包含数组的索引位置,例如:在{0,1,2,3,1,2,3}中索引{2,3},则返回3。
|
||||
/// </summary>
|
||||
/// <param name="srcByteArray"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="subByteArray"></param>
|
||||
/// <returns></returns>
|
||||
public static int IndexOfFirst(this byte[] srcByteArray, int offset, int length, byte[] subByteArray)
|
||||
{
|
||||
if (length < subByteArray.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int hitLength = 0;
|
||||
for (int i = offset; i < length + offset; i++)
|
||||
{
|
||||
if (srcByteArray[i] == subByteArray[hitLength])
|
||||
{
|
||||
hitLength++;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitLength = 0;
|
||||
}
|
||||
|
||||
if (hitLength == subByteArray.Length)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#region Json转换
|
||||
/// <summary>
|
||||
/// 序列化成Json数据
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ToJsonBytes(this object obj)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化成Json数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="len"></param>
|
||||
/// <returns></returns>
|
||||
public static T ToJsonObject<T>(this byte[] buffer, int offset, int len)
|
||||
{
|
||||
return Encoding.UTF8.GetString(buffer, offset, len).ToJsonObject<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化成Json数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="buffer"></param>
|
||||
/// <returns></returns>
|
||||
public static T ToJsonObject<T>(this byte[] buffer)
|
||||
{
|
||||
return Encoding.UTF8.GetString(buffer).ToJsonObject<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化成Json数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="jsonString"></param>
|
||||
/// <returns></returns>
|
||||
public static T ToJsonObject<T>(this string jsonString)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(jsonString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化成Json数据
|
||||
/// </summary>
|
||||
/// <param name="jsonString"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object ToJsonObject(this string jsonString, Type type)
|
||||
{
|
||||
return JsonConvert.DeserializeObject(jsonString, type);
|
||||
}
|
||||
|
||||
#endregion Json转换
|
||||
|
||||
/// <summary>
|
||||
/// 只按第一个匹配项分割
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="split"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] SplitFirst(this string str, char split)
|
||||
{
|
||||
List<string> s = new List<string>();
|
||||
int index = str.IndexOf(split);
|
||||
if (index > 0)
|
||||
{
|
||||
s.Add(str.Substring(0, index).Trim());
|
||||
s.Add(str.Substring(index + 1, str.Length - index - 1).Trim());
|
||||
}
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按字符串分割
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] Split(this string str, string pattern)
|
||||
{
|
||||
return Regex.Split(str, pattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 只按最后一个匹配项分割
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="split"></param>
|
||||
/// <returns></returns>
|
||||
public static string[] SplitLast(this string str, char split)
|
||||
{
|
||||
List<string> s = new List<string>();
|
||||
int index = str.LastIndexOf(split);
|
||||
if (index > 0)
|
||||
{
|
||||
s.Add(str.Substring(0, index).Trim());
|
||||
s.Add(str.Substring(index + 1, str.Length - index - 1).Trim());
|
||||
}
|
||||
|
||||
return s.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将字符串转换为指定类型
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object ParseToType(this string str, Type type)
|
||||
{
|
||||
dynamic obj = null;
|
||||
if (type == RRQMReadonly.stringType)
|
||||
{
|
||||
obj = str;
|
||||
}
|
||||
else if (type == RRQMReadonly.byteType)
|
||||
{
|
||||
obj = byte.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.boolType)
|
||||
{
|
||||
obj = bool.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.shortType)
|
||||
{
|
||||
obj = short.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.intType)
|
||||
{
|
||||
obj = int.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.longType)
|
||||
{
|
||||
obj = long.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.floatType)
|
||||
{
|
||||
obj = float.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.doubleType)
|
||||
{
|
||||
obj = double.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.decimalType)
|
||||
{
|
||||
obj = decimal.Parse(str);
|
||||
}
|
||||
else if (type == RRQMReadonly.dateTimeType)
|
||||
{
|
||||
obj = DateTime.Parse(str);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按格式填充
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="ps"></param>
|
||||
/// <returns></returns>
|
||||
public static string Format(this string str, params object[] ps)
|
||||
{
|
||||
return string.Format(str, ps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为SHA1。
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ToSha1(this string value, Encoding encoding)
|
||||
{
|
||||
SHA1 sha1 = new SHA1CryptoServiceProvider();
|
||||
return sha1.ComputeHash(encoding.GetBytes(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为UTF-8数据
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ToUTF8Bytes(this string value)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取自定义attribute
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="enumObj"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetAttribute<T>(this Enum enumObj) where T : Attribute
|
||||
{
|
||||
Type type = enumObj.GetType();
|
||||
Attribute attr = null;
|
||||
string enumName = Enum.GetName(type, enumObj); //获取对应的枚举名
|
||||
FieldInfo field = type.GetField(enumName);
|
||||
attr = field.GetCustomAttribute(typeof(T), false);
|
||||
return (T)attr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 格林尼治标准时间
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <param name="v"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToGMTString(this DateTime dt, string v)
|
||||
{
|
||||
return dt.ToString("r", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有成员
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="queue"></param>
|
||||
public static void Clear<T>(this ConcurrentQueue<T> queue)
|
||||
{
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
queue.Clear();
|
||||
#else
|
||||
while (queue.TryDequeue(out _))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转Base64。
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToBase64(this byte[] data)
|
||||
{
|
||||
return Convert.ToBase64String(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取字节中的指定Bit的值
|
||||
/// </summary>
|
||||
/// <param name="this">字节</param>
|
||||
/// <param name="index">Bit的索引值(0-7)</param>
|
||||
/// <returns></returns>
|
||||
public static int GetBit(this byte @this, short index)
|
||||
{
|
||||
byte x = 1;
|
||||
switch (index)
|
||||
{
|
||||
case 0: { x = 0x01; } break;
|
||||
case 1: { x = 0x02; } break;
|
||||
case 2: { x = 0x04; } break;
|
||||
case 3: { x = 0x08; } break;
|
||||
case 4: { x = 0x10; } break;
|
||||
case 5: { x = 0x20; } break;
|
||||
case 6: { x = 0x40; } break;
|
||||
case 7: { x = 0x80; } break;
|
||||
default: { return 0; }
|
||||
}
|
||||
return (@this & x) == x ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置字节中的指定Bit的值
|
||||
/// </summary>
|
||||
/// <param name="this">字节</param>
|
||||
/// <param name="index">Bit的索引值(0-7)</param>
|
||||
/// <param name="bitvalue">Bit值(0,1)</param>
|
||||
/// <returns></returns>
|
||||
public static byte SetBit(this byte @this, short index, int bitvalue)
|
||||
{
|
||||
var _byte = @this;
|
||||
if (bitvalue == 1)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: { return _byte |= 0x01; }
|
||||
case 1: { return _byte |= 0x02; }
|
||||
case 2: { return _byte |= 0x04; }
|
||||
case 3: { return _byte |= 0x08; }
|
||||
case 4: { return _byte |= 0x10; }
|
||||
case 5: { return _byte |= 0x20; }
|
||||
case 6: { return _byte |= 0x40; }
|
||||
case 7: { return _byte |= 0x80; }
|
||||
default: { return _byte; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: { return _byte &= 0xFE; }
|
||||
case 1: { return _byte &= 0xFD; }
|
||||
case 2: { return _byte &= 0xFB; }
|
||||
case 3: { return _byte &= 0xF7; }
|
||||
case 4: { return _byte &= 0xEF; }
|
||||
case 5: { return _byte &= 0xDF; }
|
||||
case 6: { return _byte &= 0xBF; }
|
||||
case 7: { return _byte &= 0x7F; }
|
||||
default: { return _byte; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转utf-8字符串
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToUtf8String(this ByteBlock byteBlock, int offset, int length)
|
||||
{
|
||||
return Encoding.UTF8.GetString(byteBlock.Buffer, offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetRefOutType(this Type type)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
{
|
||||
return type.GetElementType();
|
||||
}
|
||||
else
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认值
|
||||
/// </summary>
|
||||
/// <param name="targetType"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetDefault(this Type targetType)
|
||||
{
|
||||
return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断为结构体
|
||||
/// </summary>
|
||||
/// <param name="targetType"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsStruct(this Type targetType)
|
||||
{
|
||||
if (!targetType.IsPrimitive && !targetType.IsClass && !targetType.IsEnum && targetType.IsValueType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
144
RRQMCore/IO/ConsoleAction.cs
Normal file
144
RRQMCore/IO/ConsoleAction.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMCore.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制台行为
|
||||
/// </summary>
|
||||
public class ConsoleAction
|
||||
{
|
||||
|
||||
private string helpOrder;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="helpOrder">帮助信息指令,如:"h|help|?"</param>
|
||||
public ConsoleAction(string helpOrder)
|
||||
{
|
||||
this.helpOrder = helpOrder;
|
||||
|
||||
this.Add(helpOrder, "帮助信息", () =>
|
||||
{
|
||||
List<string> s = new List<string>();
|
||||
foreach (var item in this.actions)
|
||||
{
|
||||
if (!s.Contains(item.Value.FullOrder.ToLower()))
|
||||
{
|
||||
s.Add(item.Value.FullOrder.ToLower());
|
||||
Console.WriteLine($"[{item.Value.FullOrder}]-------->{item.Value.Description}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 帮助信息指令
|
||||
/// </summary>
|
||||
public string HelpOrder
|
||||
{
|
||||
get { return this.helpOrder; }
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<string, VAction> actions = new Dictionary<string, VAction>();
|
||||
|
||||
/// <summary>
|
||||
/// 添加
|
||||
/// </summary>
|
||||
/// <param name="order">指令,多个指令用“|”分割</param>
|
||||
/// <param name="description">描述</param>
|
||||
/// <param name="action"></param>
|
||||
public void Add(string order, string description, Action action)
|
||||
{
|
||||
string[] orders = order.ToLower().Split('|');
|
||||
foreach (var item in orders)
|
||||
{
|
||||
this.actions.Add(item, new VAction(description, order, action));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行异常
|
||||
/// </summary>
|
||||
public event Action<Exception> OnException;
|
||||
|
||||
/// <summary>
|
||||
/// 执行,返回值仅表示是否有这个指令,异常获取请使用<see cref="OnException"/>
|
||||
/// </summary>
|
||||
/// <param name="order"></param>
|
||||
/// <returns></returns>
|
||||
public bool Run(string order)
|
||||
{
|
||||
if (this.actions.TryGetValue(order.ToLower(), out VAction vAction))
|
||||
{
|
||||
try
|
||||
{
|
||||
vAction.Action.Invoke();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.OnException?.Invoke(ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct VAction
|
||||
{
|
||||
private Action action;
|
||||
|
||||
public Action Action
|
||||
{
|
||||
get { return this.action; }
|
||||
}
|
||||
|
||||
private string fullOrder;
|
||||
|
||||
public string FullOrder
|
||||
{
|
||||
get { return this.fullOrder; }
|
||||
}
|
||||
|
||||
|
||||
private string description;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="description"></param>
|
||||
/// <param name="fullOrder"></param>
|
||||
public VAction(string description, string fullOrder, Action action)
|
||||
{
|
||||
this.fullOrder = fullOrder;
|
||||
this.action = action ?? throw new ArgumentNullException(nameof(action));
|
||||
this.description = description ?? throw new ArgumentNullException(nameof(description));
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return this.description; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
147
RRQMCore/IO/FileControler.cs
Normal file
147
RRQMCore/IO/FileControler.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RRQMCore.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件操作
|
||||
/// </summary>
|
||||
public static class FileControler
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得文件Hash值
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径</param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
HashAlgorithm hash = SHA256.Create();
|
||||
using (FileStream fileStream = File.OpenRead(filePath))
|
||||
{
|
||||
byte[] HashValue = hash.ComputeHash(fileStream);
|
||||
return BitConverter.ToString(HashValue).Replace("-", "");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得流Hash值
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetStreamHash(Stream stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
HashAlgorithm hash = SHA256.Create();
|
||||
byte[] HashValue = hash.ComputeHash(stream);
|
||||
return BitConverter.ToString(HashValue).Replace("-", "");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得文件Hash值
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径</param>
|
||||
/// <param name="hash"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(string filePath, HashAlgorithm hash)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fileStream = File.OpenRead(filePath))
|
||||
{
|
||||
byte[] HashValue = hash.ComputeHash(fileStream);
|
||||
return BitConverter.ToString(HashValue).Replace("-", "");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得流Hash值
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="hash"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetStreamHash(Stream stream, HashAlgorithm hash)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] HashValue = hash.ComputeHash(stream);
|
||||
return BitConverter.ToString(HashValue).Replace("-", "");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
# if NET45_OR_GREATER
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
private const int OF_READWRITE = 2;
|
||||
|
||||
private const int OF_SHARE_DENY_NONE = 0x40;
|
||||
|
||||
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
|
||||
|
||||
/// <summary>
|
||||
/// 判断文件是否被已打开
|
||||
/// </summary>
|
||||
/// <param name="fileFullName"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FileIsOpen(string fileFullName)
|
||||
{
|
||||
if (!File.Exists(fileFullName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr handle = _lopen(fileFullName, OF_READWRITE | OF_SHARE_DENY_NONE);
|
||||
|
||||
if (handle == HFILE_ERROR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
69
RRQMCore/Logger/ConsoleLogger.cs
Normal file
69
RRQMCore/Logger/ConsoleLogger.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制台日志记录器
|
||||
/// </summary>
|
||||
public class ConsoleLogger : ILog
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录日志
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
public virtual void Debug(LogType logType, object source, string message)
|
||||
{
|
||||
this.Debug(logType, source, message, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录日志
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public virtual void Debug(LogType logType, object source, string message, Exception exception)
|
||||
{
|
||||
Console.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff"));
|
||||
Console.Write(" | ");
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Warning:
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
break;
|
||||
case LogType.Error:
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
break;
|
||||
case LogType.Message:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Console.Write(logType.ToString());
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.Write(" | ");
|
||||
Console.Write(message);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
Console.Write(" | ");
|
||||
Console.Write($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}");
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
92
RRQMCore/Logger/FileLogger.cs
Normal file
92
RRQMCore/Logger/FileLogger.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件日志记录器
|
||||
/// <para>会在指定目录下,生成logs文件夹,然后按[yyyy-MM-dd].log的形式,每日生成日志</para>
|
||||
/// </summary>
|
||||
public class FileLogger : ILog
|
||||
{
|
||||
private readonly string rootPath;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="rootPath">日志根目录</param>
|
||||
public FileLogger(string rootPath = null)
|
||||
{
|
||||
this.rootPath = Path.Combine(rootPath == null ? AppDomain.CurrentDomain.BaseDirectory : rootPath, "logs");
|
||||
if (!Directory.Exists(this.rootPath))
|
||||
{
|
||||
Directory.CreateDirectory(this.rootPath);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
public void Debug(LogType logType, object source, string message)
|
||||
{
|
||||
this.Debug(logType, source, message, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public void Debug(LogType logType, object source, string message, Exception exception)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.Append(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff"));
|
||||
stringBuilder.Append(" | ");
|
||||
stringBuilder.Append(logType.ToString());
|
||||
stringBuilder.Append(" | ");
|
||||
stringBuilder.Append(message);
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
stringBuilder.Append(" | ");
|
||||
stringBuilder.Append($"【堆栈】:{(exception == null ? "未知" : exception.StackTrace)}");
|
||||
}
|
||||
stringBuilder.AppendLine();
|
||||
|
||||
this.Print(stringBuilder.ToString());
|
||||
}
|
||||
|
||||
private void Print(string logString)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
string path = Path.Combine(this.rootPath, DateTime.Now.ToString("[yyyy-MM-dd]") + ".log");
|
||||
File.AppendAllText(path, logString);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
RRQMCore/Logger/ILog.cs
Normal file
40
RRQMCore/Logger/ILog.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志接口
|
||||
/// </summary>
|
||||
public interface ILog
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志记录
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
void Debug(LogType logType, object source, string message, Exception exception);
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
void Debug(LogType logType, object source, string message);
|
||||
}
|
||||
}
|
||||
36
RRQMCore/Logger/LogType.cs
Normal file
36
RRQMCore/Logger/LogType.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志类型
|
||||
/// </summary>
|
||||
public enum LogType
|
||||
{
|
||||
/// <summary>
|
||||
/// 一般消息
|
||||
/// </summary>
|
||||
Message,
|
||||
|
||||
/// <summary>
|
||||
/// 警示消息
|
||||
/// </summary>
|
||||
Warning,
|
||||
|
||||
/// <summary>
|
||||
/// 错误消息
|
||||
/// </summary>
|
||||
Error
|
||||
}
|
||||
}
|
||||
102
RRQMCore/Logger/LoggerGroup.cs
Normal file
102
RRQMCore/Logger/LoggerGroup.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Log
|
||||
{
|
||||
/// <summary>
|
||||
/// 一组日志记录器
|
||||
/// </summary>
|
||||
public class LoggerGroup : ILog
|
||||
{
|
||||
private readonly ILog[] logs;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="logs"></param>
|
||||
public LoggerGroup(params ILog[] logs)
|
||||
{
|
||||
this.logs = logs ?? throw new ArgumentNullException(nameof(logs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public void Debug(LogType logType, object source, string message, Exception exception)
|
||||
{
|
||||
foreach (var log in this.logs)
|
||||
{
|
||||
try
|
||||
{
|
||||
log.Debug(logType, source, message, exception);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc/>
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
public void Debug(LogType logType, object source, string message)
|
||||
{
|
||||
this.Debug(logType, source, message, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定类型的记录器输出
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public void Debug<T>(LogType logType, object source, string message, Exception exception) where T : ILog
|
||||
{
|
||||
foreach (var log in this.logs)
|
||||
{
|
||||
if (log.GetType() == typeof(T))
|
||||
{
|
||||
try
|
||||
{
|
||||
log.Debug(logType, source, message, exception);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定类型的记录器输出
|
||||
/// </summary>
|
||||
/// <param name="logType"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="message"></param>
|
||||
public void Debug<T>(LogType logType, object source, string message) where T : ILog
|
||||
{
|
||||
this.Debug(logType, source, message, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
RRQMCore/Pool/ObjectPool/IObjectPool.cs
Normal file
32
RRQMCore/Pool/ObjectPool/IObjectPool.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Pool
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象池接口
|
||||
/// </summary>
|
||||
public interface IObjectPool : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 可使用数量
|
||||
/// </summary>
|
||||
int FreeSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 清空池中对象
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
}
|
||||
41
RRQMCore/Pool/ObjectPool/IPoolObject.cs
Normal file
41
RRQMCore/Pool/ObjectPool/IPoolObject.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Pool
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象池单位接口
|
||||
/// </summary>
|
||||
public interface IPoolObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否为新建对象
|
||||
/// </summary>
|
||||
bool NewCreate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初创建对象
|
||||
/// </summary>
|
||||
void Create();
|
||||
|
||||
/// <summary>
|
||||
/// 重新创建对象
|
||||
/// </summary>
|
||||
void Recreate();
|
||||
|
||||
/// <summary>
|
||||
/// 销毁对象
|
||||
/// </summary>
|
||||
void Destroy();
|
||||
}
|
||||
}
|
||||
148
RRQMCore/Pool/ObjectPool/ObjectPool.cs
Normal file
148
RRQMCore/Pool/ObjectPool/ObjectPool.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Pool
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象池
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class ObjectPool<T> : IObjectPool where T : IPoolObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public ObjectPool(int capacity)
|
||||
{
|
||||
this.Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ObjectPool()
|
||||
{
|
||||
}
|
||||
|
||||
private ConcurrentQueue<T> queue = new ConcurrentQueue<T>();
|
||||
|
||||
private bool autoCreate = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动生成
|
||||
/// </summary>
|
||||
public bool AutoCreate
|
||||
{
|
||||
get { return this.autoCreate; }
|
||||
set { this.autoCreate = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对象池容量
|
||||
/// </summary>
|
||||
public int Capacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可使用(创建)数量
|
||||
/// </summary>
|
||||
public int FreeSize
|
||||
{ get { return this.freeSize; } }
|
||||
|
||||
private int freeSize;
|
||||
|
||||
/// <summary>
|
||||
/// 清除池中所有对象
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
while (this.queue.TryDequeue(out _))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象T
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T GetObject()
|
||||
{
|
||||
T t;
|
||||
if (this.queue.TryDequeue(out t))
|
||||
{
|
||||
t.Recreate();
|
||||
t.NewCreate = false;
|
||||
Interlocked.Decrement(ref this.freeSize);
|
||||
return t;
|
||||
}
|
||||
if (this.autoCreate)
|
||||
{
|
||||
t = (T)Activator.CreateInstance(typeof(T));
|
||||
t.Create();
|
||||
t.NewCreate = true;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T[] GetAllObject()
|
||||
{
|
||||
List<T> ts = new List<T>();
|
||||
while (this.queue.TryDequeue(out T t))
|
||||
{
|
||||
ts.Add(t);
|
||||
}
|
||||
return ts.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预获取
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public T PreviewGetObject()
|
||||
{
|
||||
T t;
|
||||
this.queue.TryPeek(out t);
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注销对象
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
public void DestroyObject(T t)
|
||||
{
|
||||
t.Destroy();
|
||||
if (this.freeSize < this.Capacity)
|
||||
{
|
||||
Interlocked.Increment(ref this.freeSize);
|
||||
this.queue.Enqueue(t);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放对象
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
RRQMCore/RRQM.ico
Normal file
BIN
RRQMCore/RRQM.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMCore/RRQM.png
Normal file
BIN
RRQMCore/RRQM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
92
RRQMCore/RRQMCore.csproj
Normal file
92
RRQMCore/RRQMCore.csproj
Normal file
@@ -0,0 +1,92 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;net5;netcoreapp3.1;netstandard2.0</TargetFrameworks>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Copyright>Copyright © 2022 若汝棋茗</Copyright>
|
||||
<Version>7.0.1</Version>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<Description>此程序集是RRQM的核心开源库,其中包含了内存池、高性能序列化、日志接口在内的很多基本内容。
|
||||
|
||||
更新内容:
|
||||
增加:AppConfigBase,更加方便的使用APP配置文件。
|
||||
增加:FileLogger,将日志按日期在本地文件保存。
|
||||
增加:LoggerGroup,能够在一个日志记录中,使用多个记录器。
|
||||
修改:Log修改为ConsoleLogger,将日志进行控制台输出。
|
||||
|
||||
特别说明:本程序集在源码里内嵌了Newtonsoft.Json 11.0.3,但为防止冲突,已修改其命名空间。
|
||||
特此感谢其作者!!!
|
||||
附带其Github:https://github.com/JamesNK/Newtonsoft.Json</Description>
|
||||
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
|
||||
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
|
||||
<ApplicationIcon>RRQM.ico</ApplicationIcon>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageTags>MemoryPool,ObjectPool,Serialize,Tool</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net5|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net5\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net5|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net5\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMCore.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="RRQM.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="RRQMCore\Resource.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resource.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Resource.resx">
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
<CustomToolNamespace>RRQMCore</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="RRQMCore\Resource.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||
<CustomToolNamespace>RRQMCore</CustomToolNamespace>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
324
RRQMCore/Resource.Designer.cs
generated
Normal file
324
RRQMCore/Resource.Designer.cs
generated
Normal file
@@ -0,0 +1,324 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本:4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将会丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Resource {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resource() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RRQMCore.Resource", typeof(Resource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 参数‘{0}’为空。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ArgumentNull {
|
||||
get {
|
||||
return ResourceManager.GetString("ArgumentNull", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 内存块已释放。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ByteBlockDisposed {
|
||||
get {
|
||||
return ResourceManager.GetString("ByteBlockDisposed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 取消操作 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Canceled {
|
||||
get {
|
||||
return ResourceManager.GetString("Canceled", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 没有找到ID为{0}的客户端。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ClientNotFind {
|
||||
get {
|
||||
return ResourceManager.GetString("ClientNotFind", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 从‘{0}’创建写入流失败,信息:{1}。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string CreateWriteStreamFail {
|
||||
get {
|
||||
return ResourceManager.GetString("CreateWriteStreamFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 默认设置值。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Default {
|
||||
get {
|
||||
return ResourceManager.GetString("Default", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 发生未知错误。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Error {
|
||||
get {
|
||||
return ResourceManager.GetString("Error", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 名称为“{0}”的事件已存在。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string EventExisted {
|
||||
get {
|
||||
return ResourceManager.GetString("EventExisted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 名称为“{0}”的事件不存在。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string EventNotExist {
|
||||
get {
|
||||
return ResourceManager.GetString("EventNotExist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 其他异常消息。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Exception {
|
||||
get {
|
||||
return ResourceManager.GetString("Exception", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 文件‘{0}’已存在。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string FileExists {
|
||||
get {
|
||||
return ResourceManager.GetString("FileExists", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 事件操作器异常。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string GetEventArgsFail {
|
||||
get {
|
||||
return ResourceManager.GetString("GetEventArgsFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 从‘{0}’路径加载流异常,信息:‘{1}’。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string LoadStreamFail {
|
||||
get {
|
||||
return ResourceManager.GetString("LoadStreamFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Token消息为‘{0}’的未注册。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string MessageNotFound {
|
||||
get {
|
||||
return ResourceManager.GetString("MessageNotFound", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 长时间没有响应。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string NoResponse {
|
||||
get {
|
||||
return ResourceManager.GetString("NoResponse", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 数据处理适配器为空,可能客户端已掉线。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string NullDataAdapter {
|
||||
get {
|
||||
return ResourceManager.GetString("NullDataAdapter", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 操作超时 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Overtime {
|
||||
get {
|
||||
return ResourceManager.GetString("Overtime", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 参数‘{0}’设置的路径‘{1}’不合法。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string PathInvalid {
|
||||
get {
|
||||
return ResourceManager.GetString("PathInvalid", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 远程终端异常,信息:{0}。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string RemoteException {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteException", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 远程文件‘{0}’不存在。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string RemoteFileNotExists {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteFileNotExists", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 远程终端不支持响应该操作。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string RemoteNotSupported {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteNotSupported", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 远程终端拒绝该操作,反馈信息:{0}。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string RemoteRefuse {
|
||||
get {
|
||||
return ResourceManager.GetString("RemoteRefuse", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 通道设置失败。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string SetChannelFail {
|
||||
get {
|
||||
return ResourceManager.GetString("SetChannelFail", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 接收流容器为空。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string StreamBucketNull {
|
||||
get {
|
||||
return ResourceManager.GetString("StreamBucketNull", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 没有找到路径‘{0}’对应的流文件。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string StreamNotFind {
|
||||
get {
|
||||
return ResourceManager.GetString("StreamNotFind", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string StreamReferencing {
|
||||
get {
|
||||
return ResourceManager.GetString("StreamReferencing", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 操作成功。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string Success {
|
||||
get {
|
||||
return ResourceManager.GetString("Success", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Token消息为‘{0}’的已注册。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TokenExist {
|
||||
get {
|
||||
return ResourceManager.GetString("TokenExist", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 未知原因错误。 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string UnknownError {
|
||||
get {
|
||||
return ResourceManager.GetString("UnknownError", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
207
RRQMCore/Resource.resx
Normal file
207
RRQMCore/Resource.resx
Normal file
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ArgumentNull" xml:space="preserve">
|
||||
<value>参数‘{0}’为空。</value>
|
||||
</data>
|
||||
<data name="ByteBlockDisposed" xml:space="preserve">
|
||||
<value>内存块已释放。</value>
|
||||
</data>
|
||||
<data name="Canceled" xml:space="preserve">
|
||||
<value>取消操作</value>
|
||||
</data>
|
||||
<data name="ClientNotFind" xml:space="preserve">
|
||||
<value>没有找到ID为{0}的客户端。</value>
|
||||
</data>
|
||||
<data name="CreateWriteStreamFail" xml:space="preserve">
|
||||
<value>从‘{0}’创建写入流失败,信息:{1}。</value>
|
||||
</data>
|
||||
<data name="Default" xml:space="preserve">
|
||||
<value>默认设置值。</value>
|
||||
</data>
|
||||
<data name="Error" xml:space="preserve">
|
||||
<value>发生未知错误。</value>
|
||||
</data>
|
||||
<data name="EventExisted" xml:space="preserve">
|
||||
<value>名称为“{0}”的事件已存在。</value>
|
||||
</data>
|
||||
<data name="EventNotExist" xml:space="preserve">
|
||||
<value>名称为“{0}”的事件不存在。</value>
|
||||
</data>
|
||||
<data name="Exception" xml:space="preserve">
|
||||
<value>其他异常消息。</value>
|
||||
</data>
|
||||
<data name="FileExists" xml:space="preserve">
|
||||
<value>文件‘{0}’已存在。</value>
|
||||
</data>
|
||||
<data name="GetEventArgsFail" xml:space="preserve">
|
||||
<value>事件操作器异常。</value>
|
||||
</data>
|
||||
<data name="LoadStreamFail" xml:space="preserve">
|
||||
<value>从‘{0}’路径加载流异常,信息:‘{1}’。</value>
|
||||
</data>
|
||||
<data name="MessageNotFound" xml:space="preserve">
|
||||
<value>Token消息为‘{0}’的未注册。</value>
|
||||
</data>
|
||||
<data name="NoResponse" xml:space="preserve">
|
||||
<value>长时间没有响应。</value>
|
||||
</data>
|
||||
<data name="NullDataAdapter" xml:space="preserve">
|
||||
<value>数据处理适配器为空,可能客户端已掉线。</value>
|
||||
</data>
|
||||
<data name="Overtime" xml:space="preserve">
|
||||
<value>操作超时</value>
|
||||
</data>
|
||||
<data name="PathInvalid" xml:space="preserve">
|
||||
<value>参数‘{0}’设置的路径‘{1}’不合法。</value>
|
||||
</data>
|
||||
<data name="RemoteException" xml:space="preserve">
|
||||
<value>远程终端异常,信息:{0}。</value>
|
||||
</data>
|
||||
<data name="RemoteFileNotExists" xml:space="preserve">
|
||||
<value>远程文件‘{0}’不存在。</value>
|
||||
</data>
|
||||
<data name="RemoteNotSupported" xml:space="preserve">
|
||||
<value>远程终端不支持响应该操作。</value>
|
||||
</data>
|
||||
<data name="RemoteRefuse" xml:space="preserve">
|
||||
<value>远程终端拒绝该操作,反馈信息:{0}。</value>
|
||||
</data>
|
||||
<data name="SetChannelFail" xml:space="preserve">
|
||||
<value>通道设置失败。</value>
|
||||
</data>
|
||||
<data name="StreamBucketNull" xml:space="preserve">
|
||||
<value>接收流容器为空。</value>
|
||||
</data>
|
||||
<data name="StreamNotFind" xml:space="preserve">
|
||||
<value>没有找到路径‘{0}’对应的流文件。</value>
|
||||
</data>
|
||||
<data name="StreamReferencing" xml:space="preserve">
|
||||
<value>路径‘{0}’对应的流文件,仍然被‘{1}’对象应用。</value>
|
||||
</data>
|
||||
<data name="Success" xml:space="preserve">
|
||||
<value>操作成功。</value>
|
||||
</data>
|
||||
<data name="TokenExist" xml:space="preserve">
|
||||
<value>Token消息为‘{0}’的已注册。</value>
|
||||
</data>
|
||||
<data name="UnknownError" xml:space="preserve">
|
||||
<value>未知原因错误。</value>
|
||||
</data>
|
||||
</root>
|
||||
61
RRQMCore/Run/Action/EasyAction.cs
Normal file
61
RRQMCore/Run/Action/EasyAction.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 易用组件
|
||||
/// </summary>
|
||||
public class EasyAction
|
||||
{
|
||||
/// <summary>
|
||||
/// 延迟执行
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="timeSpan"></param>
|
||||
public static void DelayRun(TimeSpan timeSpan, Action action)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(timeSpan);
|
||||
action?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 延迟执行
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="ticks"></param>
|
||||
public static void DelayRun(int ticks, Action action)
|
||||
{
|
||||
DelayRun(TimeSpan.FromMilliseconds(ticks), action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Task异步
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="statu"></param>
|
||||
/// <param name="action"></param>
|
||||
public static void TaskRun<T>(T statu, Action<T> action)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
action.Invoke(statu);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
274
RRQMCore/Run/Action/LoopAction.cs
Normal file
274
RRQMCore/Run/Action/LoopAction.cs
Normal file
@@ -0,0 +1,274 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 循环动作
|
||||
/// </summary>
|
||||
public class LoopAction : EasyAction, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 析构函数
|
||||
/// </summary>
|
||||
~LoopAction()
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
|
||||
private int executedCount;
|
||||
|
||||
private TimeSpan interval;
|
||||
|
||||
private int loopCount;
|
||||
|
||||
private EventWaitHandle waitHandle;
|
||||
|
||||
private LoopAction(int count, TimeSpan interval, Action<LoopAction> action)
|
||||
{
|
||||
this.loopCount = count;
|
||||
this.action = action;
|
||||
this.interval = interval;
|
||||
this.waitHandle = new AutoResetEvent(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建可循环操作体
|
||||
/// </summary>
|
||||
/// <param name="count">循环次数,设为-1时一直循环</param>
|
||||
/// <param name="interval">每次循环间隔</param>
|
||||
/// <param name="action">执行委托</param>
|
||||
/// <returns></returns>
|
||||
public static LoopAction CreateLoopAction(int count, TimeSpan interval, Action<LoopAction> action)
|
||||
{
|
||||
return new LoopAction(count, interval, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建可循环操作体
|
||||
/// </summary>
|
||||
/// <param name="count">循环次数,设为-1时一直循环</param>
|
||||
/// <param name="intervalMS">每次循环间隔,毫秒</param>
|
||||
/// <param name="action">执行委托</param>
|
||||
/// <returns></returns>
|
||||
public static LoopAction CreateLoopAction(int count, int intervalMS, Action<LoopAction> action)
|
||||
{
|
||||
return new LoopAction(count, TimeSpan.FromMilliseconds(intervalMS), action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建可循环操作体
|
||||
/// </summary>
|
||||
/// <param name="count">循环次数,设为-1时一直循环</param>
|
||||
/// <param name="action">执行委托</param>
|
||||
/// <returns></returns>
|
||||
public static LoopAction CreateLoopAction(int count, Action<LoopAction> action)
|
||||
{
|
||||
return CreateLoopAction(count, TimeSpan.Zero, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建可循环操作体
|
||||
/// </summary>
|
||||
/// <param name="interval">每次循环间隔</param>
|
||||
/// <param name="action">执行委托</param>
|
||||
/// <returns></returns>
|
||||
public static LoopAction CreateLoopAction(TimeSpan interval, Action<LoopAction> action)
|
||||
{
|
||||
return CreateLoopAction(-1, interval, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建可循环操作体
|
||||
/// </summary>
|
||||
/// <param name="action">执行委托</param>
|
||||
/// <returns></returns>
|
||||
public static LoopAction CreateLoopAction(Action<LoopAction> action)
|
||||
{
|
||||
return CreateLoopAction(-1, TimeSpan.Zero, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 已执行次数
|
||||
/// </summary>
|
||||
public int ExecutedCount
|
||||
{
|
||||
get { return this.executedCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行间隔
|
||||
/// </summary>
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get { return this.interval; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 循环次数
|
||||
/// </summary>
|
||||
public int LoopCount
|
||||
{
|
||||
get { return this.loopCount; }
|
||||
}
|
||||
|
||||
private Action<LoopAction> action;
|
||||
|
||||
/// <summary>
|
||||
/// 执行委托
|
||||
/// </summary>
|
||||
public Action<LoopAction> ExecuteAction
|
||||
{
|
||||
get { return this.action; }
|
||||
}
|
||||
|
||||
private RunStatus runStatus;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在运行
|
||||
/// </summary>
|
||||
public RunStatus RunStatus
|
||||
{
|
||||
get { return this.runStatus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运行
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
if (this.runStatus == RunStatus.None)
|
||||
{
|
||||
this.runStatus = RunStatus.Running;
|
||||
if (this.loopCount >= 0)
|
||||
{
|
||||
for (int i = 0; i < this.loopCount; i++)
|
||||
{
|
||||
if (this.runStatus == RunStatus.Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.action.Invoke(this);
|
||||
this.executedCount++;
|
||||
if (this.runStatus == RunStatus.Paused)
|
||||
{
|
||||
this.waitHandle.WaitOne();
|
||||
}
|
||||
this.waitHandle.WaitOne(this.interval);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (this.runStatus == RunStatus.Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.action.Invoke(this);
|
||||
this.executedCount++;
|
||||
if (this.runStatus == RunStatus.Paused)
|
||||
{
|
||||
this.waitHandle.WaitOne();
|
||||
}
|
||||
this.waitHandle.WaitOne(this.interval);
|
||||
}
|
||||
}
|
||||
this.runStatus = RunStatus.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新运行
|
||||
/// </summary>
|
||||
public void Rerun()
|
||||
{
|
||||
if (this.runStatus == RunStatus.Disposed)
|
||||
{
|
||||
throw new RRQMException("无法利用已释放的资源");
|
||||
}
|
||||
this.runStatus = RunStatus.None;
|
||||
this.Run();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以异步重新运行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task RerunAsync()
|
||||
{
|
||||
if (this.runStatus == RunStatus.Disposed)
|
||||
{
|
||||
throw new RRQMException("无法利用已释放的资源");
|
||||
}
|
||||
this.runStatus = RunStatus.None;
|
||||
return this.RunAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以异步运行
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task RunAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
this.Run();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停
|
||||
/// </summary>
|
||||
public void Pause()
|
||||
{
|
||||
if (this.runStatus == RunStatus.Running)
|
||||
{
|
||||
this.waitHandle.Reset();
|
||||
this.runStatus = RunStatus.Paused;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回复
|
||||
/// </summary>
|
||||
public void Resume()
|
||||
{
|
||||
if (this.runStatus == RunStatus.Paused)
|
||||
{
|
||||
this.runStatus = RunStatus.Running;
|
||||
this.waitHandle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.runStatus == RunStatus.Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this.runStatus == RunStatus.Completed)
|
||||
{
|
||||
this.waitHandle.Dispose();
|
||||
}
|
||||
this.runStatus = RunStatus.Disposed;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
RRQMCore/Run/Action/RunStatus.cs
Normal file
45
RRQMCore/Run/Action/RunStatus.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 运行状态
|
||||
/// </summary>
|
||||
public enum RunStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// None
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Running
|
||||
/// </summary>
|
||||
Running,
|
||||
|
||||
/// <summary>
|
||||
/// Completed
|
||||
/// </summary>
|
||||
Completed,
|
||||
|
||||
/// <summary>
|
||||
/// Pause
|
||||
/// </summary>
|
||||
Paused,
|
||||
|
||||
/// <summary>
|
||||
/// Disposed
|
||||
/// </summary>
|
||||
Disposed
|
||||
}
|
||||
}
|
||||
44
RRQMCore/Run/Message/AppMessageAttribute.cs
Normal file
44
RRQMCore/Run/Message/AppMessageAttribute.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册为消息
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
|
||||
public sealed class AppMessageAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public AppMessageAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
public AppMessageAttribute(string token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标识
|
||||
/// </summary>
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
370
RRQMCore/Run/Message/AppMessenger.cs
Normal file
370
RRQMCore/Run/Message/AppMessenger.cs
Normal file
@@ -0,0 +1,370 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息通知类
|
||||
/// </summary>
|
||||
public class AppMessenger<TMessage> where TMessage : IMessage
|
||||
{
|
||||
private bool allowMultiple = false;
|
||||
|
||||
private ConcurrentDictionary<string, List<TokenInstance>> tokenAndInstance = new ConcurrentDictionary<string, List<TokenInstance>>();
|
||||
|
||||
/// <summary>
|
||||
/// 允许多广播注册
|
||||
/// </summary>
|
||||
public bool AllowMultiple
|
||||
{
|
||||
get { return this.allowMultiple; }
|
||||
set { this.allowMultiple = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断能否触发该消息,意味着该消息是否已经注册。
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public bool CanSendMessage(string token)
|
||||
{
|
||||
return this.tokenAndInstance.ContainsKey(token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有消息
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.tokenAndInstance.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] GetAllMessage()
|
||||
{
|
||||
return this.tokenAndInstance.Keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册已加载程序集中直接或间接继承自IMassage接口的所有类,并创建新实例
|
||||
/// </summary>
|
||||
public void RegistAll()
|
||||
{
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(TMessage))))
|
||||
.ToArray();
|
||||
foreach (var v in types)
|
||||
{
|
||||
TMessage message = (TMessage)Activator.CreateInstance(v);
|
||||
this.Register(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="action"></param>
|
||||
public void Register(TMessage messageObject, Action action)
|
||||
{
|
||||
this.Register(messageObject, action.Method.Name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public void Register<T>() where T : TMessage
|
||||
{
|
||||
this.Register((T)Activator.CreateInstance(typeof(T)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <exception cref="MessageRegisteredException"></exception>
|
||||
public void Register(TMessage messageObject, string token, Action action)
|
||||
{
|
||||
if (this.allowMultiple || !this.tokenAndInstance.ContainsKey(token))
|
||||
{
|
||||
TokenInstance tokenInstance = new TokenInstance();
|
||||
tokenInstance.MessageObject = messageObject;
|
||||
tokenInstance.MethodInfo = action.Method;
|
||||
var list = this.tokenAndInstance.GetOrAdd(token, (s) => { return new List<TokenInstance>(); });
|
||||
list.Add(tokenInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageRegisteredException(ResType.TokenExist.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
public void Register(TMessage messageObject)
|
||||
{
|
||||
MethodInfo[] methods = messageObject.GetType().GetMethods();
|
||||
foreach (var method in methods)
|
||||
{
|
||||
IEnumerable<Attribute> attributes = method.GetCustomAttributes();
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute is AppMessageAttribute att)
|
||||
{
|
||||
if (string.IsNullOrEmpty(att.Token))
|
||||
{
|
||||
this.Register(messageObject, method.Name, method);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Register(messageObject, att.Token, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="methodInfo"></param>
|
||||
/// <exception cref="MessageRegisteredException"></exception>
|
||||
public void Register(TMessage messageObject, string token, MethodInfo methodInfo)
|
||||
{
|
||||
if (this.allowMultiple || !this.tokenAndInstance.ContainsKey(token))
|
||||
{
|
||||
TokenInstance tokenInstance = new TokenInstance();
|
||||
tokenInstance.MessageObject = messageObject;
|
||||
tokenInstance.MethodInfo = methodInfo;
|
||||
var list = this.tokenAndInstance.GetOrAdd(token, (s) => { return new List<TokenInstance>(); });
|
||||
list.Add(tokenInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageRegisteredException(ResType.TokenExist.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="action"></param>
|
||||
public void Register<T>(TMessage messageObject, Action<T> action)
|
||||
{
|
||||
this.Register(messageObject, action.Method.Name, action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册消息
|
||||
/// </summary>
|
||||
/// <typeparam name="T">参数类型</typeparam>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="action"></param>
|
||||
/// <exception cref="MessageRegisteredException"></exception>
|
||||
public void Register<T>(TMessage messageObject, string token, Action<T> action)
|
||||
{
|
||||
if (this.allowMultiple || !this.tokenAndInstance.ContainsKey(token))
|
||||
{
|
||||
TokenInstance tokenInstance = new TokenInstance();
|
||||
tokenInstance.MessageObject = messageObject;
|
||||
tokenInstance.MethodInfo = action.Method;
|
||||
var list = this.tokenAndInstance.GetOrAdd(token, (s) => { return new List<TokenInstance>(); });
|
||||
list.Add(tokenInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageRegisteredException(ResType.TokenExist.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册
|
||||
/// </summary>
|
||||
/// <typeparam name="T">参数类型</typeparam>
|
||||
/// <typeparam name="TReturn">返回值类型</typeparam>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="action"></param>
|
||||
public void Register<T, TReturn>(TMessage messageObject, string token, Func<T, TReturn> action)
|
||||
{
|
||||
if (this.allowMultiple || !this.tokenAndInstance.ContainsKey(token))
|
||||
{
|
||||
TokenInstance tokenInstance = new TokenInstance();
|
||||
tokenInstance.MessageObject = messageObject;
|
||||
tokenInstance.MethodInfo = action.Method;
|
||||
var list = this.tokenAndInstance.GetOrAdd(token, (s) => { return new List<TokenInstance>(); });
|
||||
list.Add(tokenInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageRegisteredException(ResType.TokenExist.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册
|
||||
/// </summary>
|
||||
/// <typeparam name="TReturn">返回值类型</typeparam>
|
||||
/// <param name="messageObject"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="action"></param>
|
||||
public void Register<TReturn>(TMessage messageObject, string token, Func<TReturn> action)
|
||||
{
|
||||
if (this.allowMultiple || !this.tokenAndInstance.ContainsKey(token))
|
||||
{
|
||||
TokenInstance tokenInstance = new TokenInstance();
|
||||
tokenInstance.MessageObject = messageObject;
|
||||
tokenInstance.MethodInfo = action.Method;
|
||||
var list = this.tokenAndInstance.GetOrAdd(token, (s) => { return new List<TokenInstance>(); });
|
||||
list.Add(tokenInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageRegisteredException(ResType.TokenExist.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <exception cref="MessageNotFoundException"></exception>
|
||||
public void Send(string token, params object[] parameters)
|
||||
{
|
||||
if (this.tokenAndInstance.TryGetValue(token, out List<TokenInstance> list))
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.MethodInfo.Invoke(item.MessageObject, parameters);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageNotFoundException(ResType.MessageNotFound.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息,当多播时,只返回最后一个返回值
|
||||
/// </summary>
|
||||
/// <typeparam name="T">返回值类型</typeparam>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="MessageNotFoundException"></exception>
|
||||
public T Send<T>(string token, params object[] parameters)
|
||||
{
|
||||
if (this.tokenAndInstance.TryGetValue(token, out List<TokenInstance> list))
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
var item = list[i];
|
||||
if (i == list.Count - 1)
|
||||
{
|
||||
return (T)item.MethodInfo.Invoke(item.MessageObject, parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.MethodInfo.Invoke(item.MessageObject, parameters);
|
||||
}
|
||||
}
|
||||
return default;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessageNotFoundException(ResType.MessageNotFound.GetResString(token));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载消息
|
||||
/// </summary>
|
||||
/// <param name="messageObject"></param>
|
||||
public void Unregister(TMessage messageObject)
|
||||
{
|
||||
List<string> key = new List<string>();
|
||||
|
||||
foreach (var item in this.tokenAndInstance.Keys)
|
||||
{
|
||||
foreach (var item2 in this.tokenAndInstance[item].ToArray())
|
||||
{
|
||||
if ((IMessage)messageObject == item2.MessageObject)
|
||||
{
|
||||
this.tokenAndInstance[item].Remove(item2);
|
||||
if (this.tokenAndInstance[item].Count == 0)
|
||||
{
|
||||
key.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in key)
|
||||
{
|
||||
this.tokenAndInstance.TryRemove(item, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载消息
|
||||
/// </summary>
|
||||
public void Unregister(string token)
|
||||
{
|
||||
this.tokenAndInstance.TryRemove(token, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息通知类
|
||||
/// </summary>
|
||||
public class AppMessenger : AppMessenger<IMessage>
|
||||
{
|
||||
private static AppMessenger instance;
|
||||
|
||||
/// <summary>
|
||||
/// 默认单例实例
|
||||
/// </summary>
|
||||
public static AppMessenger Default
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new AppMessenger();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
RRQMCore/Run/Message/IMessage.cs
Normal file
22
RRQMCore/Run/Message/IMessage.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息接口
|
||||
/// </summary>
|
||||
public interface IMessage
|
||||
{
|
||||
}
|
||||
}
|
||||
22
RRQMCore/Run/Message/TokenInstance.cs
Normal file
22
RRQMCore/Run/Message/TokenInstance.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
internal class TokenInstance
|
||||
{
|
||||
internal IMessage MessageObject { get; set; }
|
||||
internal MethodInfo MethodInfo { get; set; }
|
||||
}
|
||||
}
|
||||
36
RRQMCore/Run/WaitPool/IWaitResult.cs
Normal file
36
RRQMCore/Run/WaitPool/IWaitResult.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待返回类
|
||||
/// </summary>
|
||||
public interface IWaitResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
int Sign { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
byte Status { get; set; }
|
||||
}
|
||||
}
|
||||
142
RRQMCore/Run/WaitPool/RRQMWaitHandlePool.cs
Normal file
142
RRQMCore/Run/WaitPool/RRQMWaitHandlePool.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待处理数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class RRQMWaitHandlePool<T> : IDisposable where T : IWaitResult
|
||||
{
|
||||
private int signCount;
|
||||
|
||||
private ConcurrentDictionary<int, WaitData<T>> waitDic;
|
||||
|
||||
private ConcurrentQueue<WaitData<T>> waitQueue;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMWaitHandlePool()
|
||||
{
|
||||
this.waitDic = new ConcurrentDictionary<int, WaitData<T>>();
|
||||
this.waitQueue = new ConcurrentQueue<WaitData<T>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销毁
|
||||
/// </summary>
|
||||
/// <param name="waitData"></param>
|
||||
public void Destroy(WaitData<T> waitData)
|
||||
{
|
||||
if (waitData._dispose)
|
||||
{
|
||||
throw new RRQMException("waitData已销毁");
|
||||
}
|
||||
if (this.waitDic.TryRemove(waitData.WaitResult.Sign, out _))
|
||||
{
|
||||
waitData.Reset();
|
||||
this.waitQueue.Enqueue(waitData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var item in this.waitDic.Values)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
foreach (var item in this.waitQueue)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
this.waitDic.Clear();
|
||||
|
||||
this.waitQueue.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个可等待对象
|
||||
/// </summary>
|
||||
public WaitData<T> GetWaitData(T result)
|
||||
{
|
||||
if (this.signCount == int.MaxValue)
|
||||
{
|
||||
this.signCount = 0;
|
||||
}
|
||||
WaitData<T> waitData;
|
||||
if (this.waitQueue.TryDequeue(out waitData))
|
||||
{
|
||||
result.Sign = Interlocked.Increment(ref this.signCount);
|
||||
waitData.SetResult(result);
|
||||
this.waitDic.TryAdd(result.Sign, waitData);
|
||||
return waitData;
|
||||
}
|
||||
|
||||
waitData = new WaitData<T>();
|
||||
result.Sign = Interlocked.Increment(ref this.signCount);
|
||||
waitData.SetResult(result);
|
||||
this.waitDic.TryAdd(result.Sign, waitData);
|
||||
return waitData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 让等待对象恢复运行
|
||||
/// </summary>
|
||||
/// <param name="sign"></param>
|
||||
public void SetRun(int sign)
|
||||
{
|
||||
WaitData<T> waitData;
|
||||
if (this.waitDic.TryGetValue(sign, out waitData))
|
||||
{
|
||||
waitData.Set();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 让等待对象恢复运行
|
||||
/// </summary>
|
||||
/// <param name="sign"></param>
|
||||
/// <param name="waitResult"></param>
|
||||
public void SetRun(int sign, T waitResult)
|
||||
{
|
||||
WaitData<T> waitData;
|
||||
if (this.waitDic.TryGetValue(sign, out waitData))
|
||||
{
|
||||
waitData.Set(waitResult);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 让等待对象恢复运行
|
||||
/// </summary>
|
||||
/// <param name="waitResult"></param>
|
||||
public void SetRun(T waitResult)
|
||||
{
|
||||
WaitData<T> waitData;
|
||||
if (this.waitDic.TryGetValue(waitResult.Sign, out waitData))
|
||||
{
|
||||
waitData.Set(waitResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
150
RRQMCore/Run/WaitPool/WaitData.cs
Normal file
150
RRQMCore/Run/WaitPool/WaitData.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待数据对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class WaitData<T> : IDisposable
|
||||
{
|
||||
internal bool _dispose;
|
||||
|
||||
private WaitDataStatus status;
|
||||
|
||||
private AutoResetEvent waitHandle;
|
||||
|
||||
private T waitResult;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public WaitData()
|
||||
{
|
||||
this.waitHandle = new AutoResetEvent(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 析构函数
|
||||
/// </summary>
|
||||
~WaitData()
|
||||
{
|
||||
if (!this._dispose)
|
||||
{
|
||||
this.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public WaitDataStatus Status { get => this.status; }
|
||||
|
||||
/// <summary>
|
||||
/// 等待数据结果
|
||||
/// </summary>
|
||||
public T WaitResult
|
||||
{
|
||||
get { return this.waitResult; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消任务
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
this.status = WaitDataStatus.Canceled;
|
||||
this.waitHandle.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.status = WaitDataStatus.Disposed;
|
||||
this._dispose = true;
|
||||
this.waitResult = default;
|
||||
this.waitHandle.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset
|
||||
/// </summary>
|
||||
public bool Reset()
|
||||
{
|
||||
this.status = WaitDataStatus.Default;
|
||||
this.waitResult = default;
|
||||
return this.waitHandle.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使等待的线程继续执行
|
||||
/// </summary>
|
||||
public void Set()
|
||||
{
|
||||
this.status = WaitDataStatus.SetRunning;
|
||||
this.waitHandle.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使等待的线程继续执行
|
||||
/// </summary>
|
||||
/// <param name="waitResult">等待结果</param>
|
||||
public void Set(T waitResult)
|
||||
{
|
||||
this.waitResult = waitResult;
|
||||
this.status = WaitDataStatus.SetRunning;
|
||||
this.waitHandle.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载取消令箭
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
public void SetCancellationToken(CancellationToken cancellationToken)
|
||||
{
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationToken.Register(() =>
|
||||
{
|
||||
this.Cancel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 载入结果
|
||||
/// </summary>
|
||||
public void SetResult(T result)
|
||||
{
|
||||
this.waitResult = result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待指定毫秒
|
||||
/// </summary>
|
||||
/// <param name="millisecond"></param>
|
||||
public WaitDataStatus Wait(int millisecond)
|
||||
{
|
||||
if (!this.waitHandle.WaitOne(millisecond))
|
||||
{
|
||||
this.status = WaitDataStatus.Overtime;
|
||||
}
|
||||
return this.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
RRQMCore/Run/WaitPool/WaitDataStatus.cs
Normal file
45
RRQMCore/Run/WaitPool/WaitDataStatus.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待数据状态
|
||||
/// </summary>
|
||||
public enum WaitDataStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认
|
||||
/// </summary>
|
||||
Default,
|
||||
|
||||
/// <summary>
|
||||
/// 收到信号运行
|
||||
/// </summary>
|
||||
SetRunning,
|
||||
|
||||
/// <summary>
|
||||
/// 超时
|
||||
/// </summary>
|
||||
Overtime,
|
||||
|
||||
/// <summary>
|
||||
/// 已取消
|
||||
/// </summary>
|
||||
Canceled,
|
||||
|
||||
/// <summary>
|
||||
/// 已释放
|
||||
/// </summary>
|
||||
Disposed
|
||||
}
|
||||
}
|
||||
65
RRQMCore/Run/WaitPool/WaitResult.cs
Normal file
65
RRQMCore/Run/WaitPool/WaitResult.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Run
|
||||
{
|
||||
/// <summary>
|
||||
/// 等待返回类
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class WaitResult : IWaitResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
protected string message;
|
||||
|
||||
/// <summary>
|
||||
/// 标记号
|
||||
/// </summary>
|
||||
protected int sign;
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
protected byte status;
|
||||
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
public string Message
|
||||
{
|
||||
get { return this.message; }
|
||||
set { this.message = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记号
|
||||
/// </summary>
|
||||
public int Sign
|
||||
{
|
||||
get { return this.sign; }
|
||||
set { this.sign = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public byte Status
|
||||
{
|
||||
get { return this.status; }
|
||||
set { this.status = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 忽略的RRQN序列化
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class RRQMNonSerializedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
32
RRQMCore/Serialization/InstanceObject.cs
Normal file
32
RRQMCore/Serialization/InstanceObject.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
internal class InstanceObject
|
||||
{
|
||||
internal InstanceType instanceType;
|
||||
internal Type Type;
|
||||
internal object GetInstance()
|
||||
{
|
||||
return Activator.CreateInstance(this.Type);
|
||||
}
|
||||
internal Type[] ArgTypes;
|
||||
internal Type ArrayType;
|
||||
internal Type[] ProTypes;
|
||||
internal PropertyInfo[] Properties;
|
||||
internal MethodInfo AddMethod;
|
||||
}
|
||||
}
|
||||
23
RRQMCore/Serialization/InstanceType.cs
Normal file
23
RRQMCore/Serialization/InstanceType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
internal enum InstanceType
|
||||
{
|
||||
Class,
|
||||
List,
|
||||
Array,
|
||||
Dictionary
|
||||
}
|
||||
}
|
||||
550
RRQMCore/Serialization/RRQMBinaryFormatter.cs
Normal file
550
RRQMCore/Serialization/RRQMBinaryFormatter.cs
Normal file
@@ -0,0 +1,550 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Helper;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 该序列化以二进制方式进行,但是不支持接口、抽象类、继承类等成员的序列化。
|
||||
/// </summary>
|
||||
public class RRQMBinaryFormatter
|
||||
{
|
||||
#region Serialize
|
||||
|
||||
/// <summary>
|
||||
/// 序列化对象
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="graph">对象</param>
|
||||
public void Serialize(ByteBlock stream, object graph)
|
||||
{
|
||||
stream.Position = 1;
|
||||
this.SerializeObject(stream, graph);
|
||||
stream.Buffer[0] = 1;
|
||||
stream.SetLength(stream.Position);
|
||||
}
|
||||
|
||||
private int SerializeObject(ByteBlock stream, object graph)
|
||||
{
|
||||
int len = 0;
|
||||
byte[] data = null;
|
||||
|
||||
long startPosition = stream.Position;
|
||||
long endPosition;
|
||||
if (graph != null)
|
||||
{
|
||||
if (graph is string str)
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(str);
|
||||
}
|
||||
else if (graph is byte by)
|
||||
{
|
||||
data = new byte[] { by };
|
||||
}
|
||||
else if (graph is sbyte sby)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(sby);
|
||||
}
|
||||
else if (graph is bool b)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(b);
|
||||
}
|
||||
else if (graph is short s)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(s);
|
||||
}
|
||||
else if (graph is ushort us)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(us);
|
||||
}
|
||||
else if (graph is int i)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(i);
|
||||
}
|
||||
else if (graph is uint ui)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(ui);
|
||||
}
|
||||
else if (graph is long l)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(l);
|
||||
}
|
||||
else if (graph is ulong ul)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(ul);
|
||||
}
|
||||
else if (graph is float f)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(f);
|
||||
}
|
||||
else if (graph is double d)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(d);
|
||||
}
|
||||
else if (graph is DateTime time)
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(time.Ticks.ToString());
|
||||
}
|
||||
else if (graph is char c)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes(c);
|
||||
}
|
||||
else if (graph is Enum)
|
||||
{
|
||||
var enumValType = Enum.GetUnderlyingType(graph.GetType());
|
||||
|
||||
if (enumValType == RRQMReadonly.byteType)
|
||||
{
|
||||
data = new byte[] { (byte)graph };
|
||||
}
|
||||
else if (enumValType == RRQMReadonly.shortType)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes((short)graph);
|
||||
}
|
||||
else if (enumValType == RRQMReadonly.intType)
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes((int)graph);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = RRQMBitConverter.Default.GetBytes((long)graph);
|
||||
}
|
||||
}
|
||||
else if (graph is byte[])
|
||||
{
|
||||
data = (byte[])graph;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Position += 4;
|
||||
Type type = graph.GetType();
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||
{
|
||||
len += this.SerializeIEnumerable(stream, (IEnumerable)graph);
|
||||
}
|
||||
else
|
||||
{
|
||||
len += this.SerializeClass(stream, graph, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
len = data.Length;
|
||||
endPosition = len + startPosition + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
endPosition = stream.Position;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
endPosition = startPosition + 4;
|
||||
}
|
||||
|
||||
byte[] lenBuffer = RRQMBitConverter.Default.GetBytes(len);
|
||||
stream.Position = startPosition;
|
||||
stream.Write(lenBuffer, 0, lenBuffer.Length);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
stream.Write(data, 0, data.Length);
|
||||
}
|
||||
stream.Position = endPosition;
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
private int SerializeClass(ByteBlock stream, object obj, Type type)
|
||||
{
|
||||
int len = 0;
|
||||
if (obj != null)
|
||||
{
|
||||
PropertyInfo[] propertyInfos = GetProperties(type);
|
||||
foreach (PropertyInfo property in propertyInfos)
|
||||
{
|
||||
if (property.GetCustomAttribute<RRQMNonSerializedAttribute>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
byte[] propertyBytes = Encoding.UTF8.GetBytes(property.Name);
|
||||
if (propertyBytes.Length > byte.MaxValue)
|
||||
{
|
||||
throw new RRQMException($"属性名:{property.Name}超长");
|
||||
}
|
||||
byte lenBytes = (byte)propertyBytes.Length;
|
||||
stream.Write(lenBytes);
|
||||
stream.Write(propertyBytes, 0, propertyBytes.Length);
|
||||
len += propertyBytes.Length + 1;
|
||||
len += this.SerializeObject(stream, property.GetValue(obj, null));
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
private int SerializeIEnumerable(ByteBlock stream, IEnumerable param)
|
||||
{
|
||||
int len = 0;
|
||||
if (param != null)
|
||||
{
|
||||
long oldPosition = stream.Position;
|
||||
stream.Position += 4;
|
||||
len += 4;
|
||||
uint paramLen = 0;
|
||||
|
||||
foreach (object item in param)
|
||||
{
|
||||
paramLen++;
|
||||
len += this.SerializeObject(stream, item);
|
||||
}
|
||||
long newPosition = stream.Position;
|
||||
stream.Position = oldPosition;
|
||||
stream.Write(RRQMBitConverter.Default.GetBytes(paramLen));
|
||||
stream.Position = newPosition;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
#endregion Serialize
|
||||
|
||||
#region Deserialize
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public object Deserialize(byte[] data, int offset, Type type)
|
||||
{
|
||||
if (data[offset] != 1)
|
||||
{
|
||||
throw new RRQMException("数据流解析错误");
|
||||
}
|
||||
offset += 1;
|
||||
return this.Deserialize(type, data, ref offset);
|
||||
}
|
||||
|
||||
private dynamic Deserialize(Type type, byte[] datas, ref int offset)
|
||||
{
|
||||
dynamic obj;
|
||||
int len = RRQMBitConverter.Default.ToInt32(datas, offset);
|
||||
offset += 4;
|
||||
if (len > 0)
|
||||
{
|
||||
if (type == RRQMReadonly.stringType)
|
||||
{
|
||||
obj = Encoding.UTF8.GetString(datas, offset, len);
|
||||
}
|
||||
else if (type == RRQMReadonly.byteType)
|
||||
{
|
||||
obj = datas[offset];
|
||||
}
|
||||
else if (type == RRQMReadonly.sbyteType)
|
||||
{
|
||||
obj = (sbyte)(RRQMBitConverter.Default.ToInt16(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.boolType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToBoolean(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.shortType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToInt16(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.ushortType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToUInt16(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.intType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToInt32(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.uintType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToUInt32(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.longType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToInt64(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.ulongType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToUInt64(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.floatType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToSingle(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.doubleType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToDouble(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.decimalType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToDouble(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.charType)
|
||||
{
|
||||
obj = (RRQMBitConverter.Default.ToChar(datas, offset));
|
||||
}
|
||||
else if (type == RRQMReadonly.dateTimeType)
|
||||
{
|
||||
obj = (new DateTime(long.Parse(Encoding.UTF8.GetString(datas, offset, len))));
|
||||
}
|
||||
else if (type.BaseType == typeof(Enum))
|
||||
{
|
||||
Type enumType = Enum.GetUnderlyingType(type);
|
||||
|
||||
if (enumType == typeof(byte))
|
||||
{
|
||||
obj = Enum.ToObject(type, datas[offset]);
|
||||
}
|
||||
else if (enumType == typeof(short))
|
||||
{
|
||||
obj = Enum.ToObject(type, RRQMBitConverter.Default.ToInt16(datas, offset));
|
||||
}
|
||||
else if (enumType == typeof(int))
|
||||
{
|
||||
obj = Enum.ToObject(type, RRQMBitConverter.Default.ToInt32(datas, offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = Enum.ToObject(type, RRQMBitConverter.Default.ToInt64(datas, offset));
|
||||
}
|
||||
}
|
||||
else if (type == RRQMReadonly.bytesType)
|
||||
{
|
||||
byte[] data = new byte[len];
|
||||
Buffer.BlockCopy(datas, offset, data, 0, len);
|
||||
obj = data;
|
||||
}
|
||||
else if (type.IsClass || type.IsStruct())
|
||||
{
|
||||
obj = this.DeserializeClass(type, datas, offset, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("未定义的类型:" + type.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = type.GetDefault();
|
||||
}
|
||||
offset += len;
|
||||
return obj;
|
||||
}
|
||||
|
||||
private dynamic DeserializeClass(Type type, byte[] datas, int offset, int length)
|
||||
{
|
||||
InstanceObject instanceObject = GetOrAddInstance(type);
|
||||
|
||||
object instance;
|
||||
switch (instanceObject.instanceType)
|
||||
{
|
||||
case InstanceType.Class:
|
||||
{
|
||||
instance = instanceObject.GetInstance();
|
||||
int index = offset;
|
||||
while (offset - index < length && (length >= 4))
|
||||
{
|
||||
int len = datas[offset];
|
||||
string propertyName = Encoding.UTF8.GetString(datas, offset + 1, len);
|
||||
offset += len + 1;
|
||||
PropertyInfo propertyInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
if (propertyInfo == null)
|
||||
{
|
||||
int pLen = RRQMBitConverter.Default.ToInt32(datas, offset);
|
||||
offset += 4;
|
||||
offset += pLen;
|
||||
continue;
|
||||
}
|
||||
object obj = this.Deserialize(propertyInfo.PropertyType, datas, ref offset);
|
||||
propertyInfo.SetValue(instance, obj);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstanceType.List:
|
||||
{
|
||||
instance = instanceObject.GetInstance();
|
||||
if (length > 0)
|
||||
{
|
||||
uint paramLen = RRQMBitConverter.Default.ToUInt32(datas, offset);
|
||||
offset += 4;
|
||||
for (uint i = 0; i < paramLen; i++)
|
||||
{
|
||||
object obj = this.Deserialize(instanceObject.ArgTypes[0], datas, ref offset);
|
||||
instanceObject.AddMethod.Invoke(instance, new object[] { obj });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstanceType.Array:
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
uint paramLen = RRQMBitConverter.Default.ToUInt32(datas, offset);
|
||||
Array array = Array.CreateInstance(instanceObject.ArrayType, paramLen);
|
||||
|
||||
offset += 4;
|
||||
for (uint i = 0; i < paramLen; i++)
|
||||
{
|
||||
object obj = this.Deserialize(instanceObject.ArrayType, datas, ref offset);
|
||||
array.SetValue(obj, i);
|
||||
}
|
||||
instance = array;
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstanceType.Dictionary:
|
||||
{
|
||||
instance = instanceObject.GetInstance();
|
||||
if (length > 0)
|
||||
{
|
||||
uint paramLen = RRQMBitConverter.Default.ToUInt32(datas, offset);
|
||||
offset += 4;
|
||||
for (uint i = 0; i < paramLen; i++)
|
||||
{
|
||||
offset += 4;
|
||||
offset += datas[offset] + 1;
|
||||
object key = this.Deserialize(instanceObject.ArgTypes[0], datas, ref offset);
|
||||
|
||||
offset += datas[offset] + 1;
|
||||
object value = this.Deserialize(instanceObject.ArgTypes[1], datas, ref offset);
|
||||
if (key != null)
|
||||
{
|
||||
instanceObject.AddMethod.Invoke(instance, new object[] { key, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
instance = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
instance = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
#endregion Deserialize
|
||||
|
||||
private static PropertyInfo[] GetProperties(Type type)
|
||||
{
|
||||
return type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<string, InstanceObject> InstanceCache = new ConcurrentDictionary<string, InstanceObject>();
|
||||
|
||||
private static InstanceObject GetOrAddInstance(Type type)
|
||||
{
|
||||
if (InstanceCache.TryGetValue(type.FullName, out InstanceObject instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
if (type.IsArray && !type.IsGenericType)//数组
|
||||
{
|
||||
InstanceObject typeInfo = InstanceCache.GetOrAdd(type.FullName, (v) =>
|
||||
{
|
||||
InstanceObject instanceObject = new InstanceObject();
|
||||
instanceObject.Type = type;
|
||||
instanceObject.ArrayType = type.GetElementType();
|
||||
instanceObject.instanceType = InstanceType.Array;
|
||||
instanceObject.Properties = GetProperties(type);
|
||||
instanceObject.ProTypes = instanceObject.Properties.Select(a => a.PropertyType).ToArray();
|
||||
return instanceObject;
|
||||
});
|
||||
return typeInfo;
|
||||
}
|
||||
else if (type.IsClass || type.IsStruct())
|
||||
{
|
||||
InstanceObject typeInfo = InstanceCache.GetOrAdd(type.FullName, (v) =>
|
||||
{
|
||||
InstanceObject instanceObject = new InstanceObject();
|
||||
instanceObject.Type = type;
|
||||
instanceObject.Properties = GetProperties(type);
|
||||
instanceObject.ProTypes = instanceObject.Properties.Select(a => a.PropertyType).ToArray();
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
instanceObject.AddMethod = type.GetMethod("Add");
|
||||
instanceObject.ArgTypes = type.GetGenericArguments();
|
||||
type = type.GetGenericTypeDefinition().MakeGenericType(instanceObject.ArgTypes);
|
||||
|
||||
if (instanceObject.ArgTypes.Length == 1)
|
||||
{
|
||||
instanceObject.instanceType = InstanceType.List;
|
||||
}
|
||||
else
|
||||
{
|
||||
instanceObject.instanceType = InstanceType.Dictionary;
|
||||
}
|
||||
}
|
||||
else if (RRQMReadonly.listType.IsAssignableFrom(type))
|
||||
{
|
||||
Type baseType = type.BaseType;
|
||||
while (!baseType.IsGenericType)
|
||||
{
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
instanceObject.ArgTypes = baseType.GetGenericArguments();
|
||||
|
||||
instanceObject.AddMethod = type.GetMethod("Add");
|
||||
instanceObject.instanceType = InstanceType.List;
|
||||
}
|
||||
else if (RRQMReadonly.dicType.IsAssignableFrom(type))
|
||||
{
|
||||
Type baseType = type.BaseType;
|
||||
while (!baseType.IsGenericType)
|
||||
{
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
instanceObject.ArgTypes = baseType.GetGenericArguments();
|
||||
instanceObject.AddMethod = type.GetMethod("Add");
|
||||
instanceObject.instanceType = InstanceType.Dictionary;
|
||||
}
|
||||
else
|
||||
{
|
||||
instanceObject.instanceType = InstanceType.Class;
|
||||
}
|
||||
return instanceObject;
|
||||
});
|
||||
return typeInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
RRQMCore/Serialization/SerializationType.cs
Normal file
36
RRQMCore/Serialization/SerializationType.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化类型
|
||||
/// </summary>
|
||||
public enum SerializationType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 若汝棋茗内置
|
||||
/// </summary>
|
||||
RRQMBinary,
|
||||
|
||||
/// <summary>
|
||||
/// Json
|
||||
/// </summary>
|
||||
Json,
|
||||
|
||||
/// <summary>
|
||||
/// Xml
|
||||
/// </summary>
|
||||
Xml
|
||||
}
|
||||
}
|
||||
379
RRQMCore/Serialization/SerializeConvert.cs
Normal file
379
RRQMCore/Serialization/SerializeConvert.cs
Normal file
@@ -0,0 +1,379 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace RRQMCore.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// 高性能序列化器
|
||||
/// </summary>
|
||||
public static class SerializeConvert
|
||||
{
|
||||
#if NET45_OR_GREATER
|
||||
|
||||
#region 普通二进制序列化
|
||||
|
||||
/// <summary>
|
||||
/// 普通二进制序列化对象
|
||||
/// </summary>
|
||||
/// <param name="obj">数据对象</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] BinarySerialize(object obj)
|
||||
{
|
||||
using (MemoryStream serializeStream = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(serializeStream, obj);
|
||||
return serializeStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 二进制序列化对象至文件
|
||||
/// </summary>
|
||||
/// <param name="obj">数据对象</param>
|
||||
/// <param name="path">路径</param>
|
||||
public static void BinarySerializeToFile(object obj, string path)
|
||||
{
|
||||
using (FileStream serializeStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(serializeStream, obj);
|
||||
serializeStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 二进制序列化对象
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="obj"></param>
|
||||
public static void BinarySerialize(Stream stream, object obj)
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
bf.Serialize(stream, obj);
|
||||
}
|
||||
|
||||
#endregion 普通二进制序列化
|
||||
|
||||
#region 普通二进制反序列化
|
||||
|
||||
/// <summary>
|
||||
/// 从Byte[]中反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="binder"></param>
|
||||
/// <returns></returns>
|
||||
public static T BinaryDeserialize<T>(byte[] data, int offset, int length, SerializationBinder binder = null)
|
||||
{
|
||||
using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length))
|
||||
{
|
||||
DeserializeStream.Position = 0;
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
if (binder != null)
|
||||
{
|
||||
bf.Binder = binder;
|
||||
}
|
||||
return (T)bf.Deserialize(DeserializeStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="binder"></param>
|
||||
/// <returns></returns>
|
||||
public static object BinaryDeserialize(byte[] data, int offset, int length, SerializationBinder binder = null)
|
||||
{
|
||||
using (MemoryStream DeserializeStream = new MemoryStream(data, offset, length))
|
||||
{
|
||||
DeserializeStream.Position = 0;
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
if (binder != null)
|
||||
{
|
||||
bf.Binder = binder;
|
||||
}
|
||||
return bf.Deserialize(DeserializeStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Stream中反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="binder"></param>
|
||||
/// <returns></returns>
|
||||
public static T BinaryDeserialize<T>(Stream stream, SerializationBinder binder = null)
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
if (binder != null)
|
||||
{
|
||||
bf.Binder = binder;
|
||||
}
|
||||
return (T)bf.Deserialize(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将二进制文件数据反序列化为指定类型对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static T BinaryDeserializeFromFile<T>(string path)
|
||||
{
|
||||
using (FileStream serializeStream = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
return (T)bf.Deserialize(serializeStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将二进制数据反序列化为指定类型对象
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static T BinaryDeserialize<T>(byte[] data)
|
||||
{
|
||||
return BinaryDeserialize<T>(data, 0, data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Byte[]中反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="binder"></param>
|
||||
/// <returns></returns>
|
||||
public static T BinaryDeserialize<T>(byte[] data, SerializationBinder binder = null)
|
||||
{
|
||||
return BinaryDeserialize<T>(data, 0, data.Length, binder);
|
||||
}
|
||||
|
||||
#endregion 普通二进制反序列化
|
||||
|
||||
#endif
|
||||
|
||||
#region RRQM二进制序列化
|
||||
|
||||
/// <summary>
|
||||
/// RRQM二进制序列化对象
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static void RRQMBinarySerialize(ByteBlock stream, object obj)
|
||||
{
|
||||
RRQMBinaryFormatter bf = new RRQMBinaryFormatter();
|
||||
bf.Serialize(stream, obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RRQM二进制序列化对象
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] RRQMBinarySerialize(object obj)
|
||||
{
|
||||
using (ByteBlock byteBlock = new ByteBlock())
|
||||
{
|
||||
RRQMBinarySerialize(byteBlock, obj);
|
||||
return byteBlock.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion RRQM二进制序列化
|
||||
|
||||
#region RRQM二进制反序列化
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <returns></returns>
|
||||
public static T RRQMBinaryDeserialize<T>(byte[] data, int offset)
|
||||
{
|
||||
RRQMBinaryFormatter bf = new RRQMBinaryFormatter();
|
||||
return (T)bf.Deserialize(data, offset, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object RRQMBinaryDeserialize(byte[] data, int offset, Type type)
|
||||
{
|
||||
RRQMBinaryFormatter bf = new RRQMBinaryFormatter();
|
||||
return bf.Deserialize(data, offset, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Byte[]中反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static T RRQMBinaryDeserialize<T>(byte[] data)
|
||||
{
|
||||
return RRQMBinaryDeserialize<T>(data, 0);
|
||||
}
|
||||
|
||||
#endregion RRQM二进制反序列化
|
||||
|
||||
#region Xml序列化和反序列化
|
||||
|
||||
/// <summary>
|
||||
/// Xml序列化数据对象
|
||||
/// </summary>
|
||||
/// <param name="obj">数据对象</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static string XmlSerializeToString(object obj, Encoding encoding)
|
||||
{
|
||||
return encoding.GetString(XmlSerializeToBytes(obj));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml序列化数据对象
|
||||
/// </summary>
|
||||
/// <param name="obj">数据对象</param>
|
||||
/// <returns></returns>
|
||||
public static string XmlSerializeToString(object obj)
|
||||
{
|
||||
return XmlSerializeToString(obj, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml序列化数据对象
|
||||
/// </summary>
|
||||
/// <param name="obj">数据对象</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] XmlSerializeToBytes(object obj)
|
||||
{
|
||||
using (MemoryStream fileStream = new MemoryStream())
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(obj.GetType());
|
||||
xml.Serialize(fileStream, obj);
|
||||
return fileStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml序列化至文件
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="path"></param>
|
||||
public static void XmlSerializeToFile(object obj, string path)
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(obj.GetType());
|
||||
xml.Serialize(fileStream, obj);
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T">反序列化类型</typeparam>
|
||||
/// <param name="datas">数据</param>
|
||||
/// <returns></returns>
|
||||
public static T XmlDeserializeFromBytes<T>(byte[] datas)
|
||||
{
|
||||
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
|
||||
using (Stream xmlstream = new MemoryStream(datas))
|
||||
{
|
||||
return (T)xmlserializer.Deserialize(xmlstream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml反序列化
|
||||
/// </summary>
|
||||
/// <param name="datas"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object XmlDeserializeFromBytes(byte[] datas, Type type)
|
||||
{
|
||||
XmlSerializer xmlserializer = new XmlSerializer(type);
|
||||
using (Stream xmlstream = new MemoryStream(datas))
|
||||
{
|
||||
return xmlserializer.Deserialize(xmlstream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="xmlString">xml字符串</param>
|
||||
/// <param name="encoding">编码格式</param>
|
||||
/// <returns></returns>
|
||||
public static T XmlDeserializeFromString<T>(string xmlString, Encoding encoding)
|
||||
{
|
||||
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
|
||||
using (Stream xmlstream = new MemoryStream(encoding.GetBytes(xmlString)))
|
||||
{
|
||||
return (T)xmlserializer.Deserialize(xmlstream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <param name="xmlString">xml字符串</param>
|
||||
/// <returns></returns>
|
||||
public static T XmlDeserializeFromString<T>(string xmlString)
|
||||
{
|
||||
return XmlDeserializeFromString<T>(xmlString, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Xml反序列化
|
||||
/// </summary>
|
||||
/// <typeparam name="T">反序列化类型</typeparam>
|
||||
/// <param name="path">文件路径</param>
|
||||
/// <returns></returns>
|
||||
public static T XmlDeserializeFromFile<T>(string path)
|
||||
{
|
||||
using (Stream xmlstream = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
|
||||
return (T)xmlserializer.Deserialize(xmlstream);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Xml序列化和反序列化
|
||||
}
|
||||
}
|
||||
60
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonBinaryType.cs
Normal file
60
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonBinaryType.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
internal enum BsonBinaryType : byte
|
||||
{
|
||||
Binary = 0x00,
|
||||
Function = 0x01,
|
||||
|
||||
[Obsolete("This type has been deprecated in the BSON specification. Use Binary instead.")]
|
||||
BinaryOld = 0x02,
|
||||
|
||||
[Obsolete("This type has been deprecated in the BSON specification. Use Uuid instead.")]
|
||||
UuidOld = 0x03,
|
||||
|
||||
Uuid = 0x04,
|
||||
Md5 = 0x05,
|
||||
UserDefined = 0x80
|
||||
}
|
||||
}
|
||||
363
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
Normal file
363
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonBinaryWriter.cs
Normal file
@@ -0,0 +1,363 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
internal class BsonBinaryWriter
|
||||
{
|
||||
private static readonly Encoding Encoding = new UTF8Encoding(false);
|
||||
|
||||
private readonly BinaryWriter _writer;
|
||||
|
||||
private byte[] _largeByteBuffer;
|
||||
|
||||
public DateTimeKind DateTimeKindHandling { get; set; }
|
||||
|
||||
public BsonBinaryWriter(BinaryWriter writer)
|
||||
{
|
||||
this.DateTimeKindHandling = DateTimeKind.Utc;
|
||||
this._writer = writer;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
this._writer.Flush();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
#if HAVE_STREAM_READER_WRITER_CLOSE
|
||||
_writer.Close();
|
||||
#else
|
||||
this._writer.Dispose();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void WriteToken(BsonToken t)
|
||||
{
|
||||
this.CalculateSize(t);
|
||||
this.WriteTokenInternal(t);
|
||||
}
|
||||
|
||||
private void WriteTokenInternal(BsonToken t)
|
||||
{
|
||||
switch (t.Type)
|
||||
{
|
||||
case BsonType.Object:
|
||||
{
|
||||
BsonObject value = (BsonObject)t;
|
||||
this._writer.Write(value.CalculatedSize);
|
||||
foreach (BsonProperty property in value)
|
||||
{
|
||||
this._writer.Write((sbyte)property.Value.Type);
|
||||
this.WriteString((string)property.Name.Value, property.Name.ByteCount, null);
|
||||
this.WriteTokenInternal(property.Value);
|
||||
}
|
||||
this._writer.Write((byte)0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Array:
|
||||
{
|
||||
BsonArray value = (BsonArray)t;
|
||||
this._writer.Write(value.CalculatedSize);
|
||||
ulong index = 0;
|
||||
foreach (BsonToken c in value)
|
||||
{
|
||||
this._writer.Write((sbyte)c.Type);
|
||||
this.WriteString(index.ToString(CultureInfo.InvariantCulture), MathUtils.IntLength(index), null);
|
||||
this.WriteTokenInternal(c);
|
||||
index++;
|
||||
}
|
||||
this._writer.Write((byte)0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Integer:
|
||||
{
|
||||
BsonValue value = (BsonValue)t;
|
||||
this._writer.Write(Convert.ToInt32(value.Value, CultureInfo.InvariantCulture));
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Long:
|
||||
{
|
||||
BsonValue value = (BsonValue)t;
|
||||
this._writer.Write(Convert.ToInt64(value.Value, CultureInfo.InvariantCulture));
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Number:
|
||||
{
|
||||
BsonValue value = (BsonValue)t;
|
||||
this._writer.Write(Convert.ToDouble(value.Value, CultureInfo.InvariantCulture));
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.String:
|
||||
{
|
||||
BsonString value = (BsonString)t;
|
||||
this.WriteString((string)value.Value, value.ByteCount, value.CalculatedSize - 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Boolean:
|
||||
this._writer.Write(t == BsonBoolean.True);
|
||||
break;
|
||||
|
||||
case BsonType.Null:
|
||||
case BsonType.Undefined:
|
||||
break;
|
||||
|
||||
case BsonType.Date:
|
||||
{
|
||||
BsonValue value = (BsonValue)t;
|
||||
|
||||
long ticks = 0;
|
||||
|
||||
if (value.Value is DateTime)
|
||||
{
|
||||
DateTime dateTime = (DateTime)value.Value;
|
||||
if (this.DateTimeKindHandling == DateTimeKind.Utc)
|
||||
{
|
||||
dateTime = dateTime.ToUniversalTime();
|
||||
}
|
||||
else if (this.DateTimeKindHandling == DateTimeKind.Local)
|
||||
{
|
||||
dateTime = dateTime.ToLocalTime();
|
||||
}
|
||||
|
||||
ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTime, false);
|
||||
}
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
else
|
||||
{
|
||||
DateTimeOffset dateTimeOffset = (DateTimeOffset)value.Value;
|
||||
ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(dateTimeOffset.UtcDateTime, dateTimeOffset.Offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
this._writer.Write(ticks);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Binary:
|
||||
{
|
||||
BsonBinary value = (BsonBinary)t;
|
||||
|
||||
byte[] data = (byte[])value.Value;
|
||||
this._writer.Write(data.Length);
|
||||
this._writer.Write((byte)value.BinaryType);
|
||||
this._writer.Write(data);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Oid:
|
||||
{
|
||||
BsonValue value = (BsonValue)t;
|
||||
|
||||
byte[] data = (byte[])value.Value;
|
||||
this._writer.Write(data);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.Regex:
|
||||
{
|
||||
BsonRegex value = (BsonRegex)t;
|
||||
|
||||
this.WriteString((string)value.Pattern.Value, value.Pattern.ByteCount, null);
|
||||
this.WriteString((string)value.Options.Value, value.Options.ByteCount, null);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteString(string s, int byteCount, int? calculatedlengthPrefix)
|
||||
{
|
||||
if (calculatedlengthPrefix != null)
|
||||
{
|
||||
this._writer.Write(calculatedlengthPrefix.GetValueOrDefault());
|
||||
}
|
||||
|
||||
this.WriteUtf8Bytes(s, byteCount);
|
||||
|
||||
this._writer.Write((byte)0);
|
||||
}
|
||||
|
||||
public void WriteUtf8Bytes(string s, int byteCount)
|
||||
{
|
||||
if (s != null)
|
||||
{
|
||||
if (byteCount <= 256)
|
||||
{
|
||||
if (this._largeByteBuffer == null)
|
||||
{
|
||||
this._largeByteBuffer = new byte[256];
|
||||
}
|
||||
|
||||
Encoding.GetBytes(s, 0, s.Length, this._largeByteBuffer, 0);
|
||||
this._writer.Write(this._largeByteBuffer, 0, byteCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytes = Encoding.GetBytes(s);
|
||||
this._writer.Write(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int CalculateSize(int stringByteCount)
|
||||
{
|
||||
return stringByteCount + 1;
|
||||
}
|
||||
|
||||
private int CalculateSizeWithLength(int stringByteCount, bool includeSize)
|
||||
{
|
||||
int baseSize = (includeSize)
|
||||
? 5 // size bytes + terminator
|
||||
: 1; // terminator
|
||||
|
||||
return baseSize + stringByteCount;
|
||||
}
|
||||
|
||||
private int CalculateSize(BsonToken t)
|
||||
{
|
||||
switch (t.Type)
|
||||
{
|
||||
case BsonType.Object:
|
||||
{
|
||||
BsonObject value = (BsonObject)t;
|
||||
|
||||
int bases = 4;
|
||||
foreach (BsonProperty p in value)
|
||||
{
|
||||
int size = 1;
|
||||
size += this.CalculateSize(p.Name);
|
||||
size += this.CalculateSize(p.Value);
|
||||
|
||||
bases += size;
|
||||
}
|
||||
bases += 1;
|
||||
value.CalculatedSize = bases;
|
||||
return bases;
|
||||
}
|
||||
case BsonType.Array:
|
||||
{
|
||||
BsonArray value = (BsonArray)t;
|
||||
|
||||
int size = 4;
|
||||
ulong index = 0;
|
||||
foreach (BsonToken c in value)
|
||||
{
|
||||
size += 1;
|
||||
size += this.CalculateSize(MathUtils.IntLength(index));
|
||||
size += this.CalculateSize(c);
|
||||
index++;
|
||||
}
|
||||
size += 1;
|
||||
value.CalculatedSize = size;
|
||||
|
||||
return value.CalculatedSize;
|
||||
}
|
||||
case BsonType.Integer:
|
||||
return 4;
|
||||
|
||||
case BsonType.Long:
|
||||
return 8;
|
||||
|
||||
case BsonType.Number:
|
||||
return 8;
|
||||
|
||||
case BsonType.String:
|
||||
{
|
||||
BsonString value = (BsonString)t;
|
||||
string s = (string)value.Value;
|
||||
value.ByteCount = (s != null) ? Encoding.GetByteCount(s) : 0;
|
||||
value.CalculatedSize = this.CalculateSizeWithLength(value.ByteCount, value.IncludeLength);
|
||||
|
||||
return value.CalculatedSize;
|
||||
}
|
||||
case BsonType.Boolean:
|
||||
return 1;
|
||||
|
||||
case BsonType.Null:
|
||||
case BsonType.Undefined:
|
||||
return 0;
|
||||
|
||||
case BsonType.Date:
|
||||
return 8;
|
||||
|
||||
case BsonType.Binary:
|
||||
{
|
||||
BsonBinary value = (BsonBinary)t;
|
||||
|
||||
byte[] data = (byte[])value.Value;
|
||||
value.CalculatedSize = 4 + 1 + data.Length;
|
||||
|
||||
return value.CalculatedSize;
|
||||
}
|
||||
case BsonType.Oid:
|
||||
return 12;
|
||||
|
||||
case BsonType.Regex:
|
||||
{
|
||||
BsonRegex value = (BsonRegex)t;
|
||||
int size = 0;
|
||||
size += this.CalculateSize(value.Pattern);
|
||||
size += this.CalculateSize(value.Options);
|
||||
value.CalculatedSize = size;
|
||||
|
||||
return value.CalculatedSize;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(t), "Unexpected token when writing BSON: {0}".FormatWith(CultureInfo.InvariantCulture, t.Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonObjectId.cs
Normal file
73
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonObjectId.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a BSON Oid (object id).
|
||||
/// </summary>
|
||||
[Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/RRQMCore.XREF.Newtonsoft.Json.Bson for more details.")]
|
||||
public class BsonObjectId
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Oid.
|
||||
/// </summary>
|
||||
/// <value>The value of the Oid.</value>
|
||||
public byte[] Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonObjectId"/> class.
|
||||
/// </summary>
|
||||
/// <param name="value">The Oid value.</param>
|
||||
public BsonObjectId(byte[] value)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(value, nameof(value));
|
||||
if (value.Length != 12)
|
||||
{
|
||||
throw new ArgumentException("An ObjectId must be 12 bytes", nameof(value));
|
||||
}
|
||||
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
871
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonReader.cs
Normal file
871
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonReader.cs
Normal file
@@ -0,0 +1,871 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a reader that provides fast, non-cached, forward-only access to serialized BSON data.
|
||||
/// </summary>
|
||||
[Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/RRQMCore.XREF.Newtonsoft.Json.Bson for more details.")]
|
||||
public class BsonReader : JsonReader
|
||||
{
|
||||
private const int MaxCharBytesSize = 128;
|
||||
private static readonly byte[] SeqRange1 = new byte[] { 0, 127 }; // range of 1-byte sequence
|
||||
private static readonly byte[] SeqRange2 = new byte[] { 194, 223 }; // range of 2-byte sequence
|
||||
private static readonly byte[] SeqRange3 = new byte[] { 224, 239 }; // range of 3-byte sequence
|
||||
private static readonly byte[] SeqRange4 = new byte[] { 240, 244 }; // range of 4-byte sequence
|
||||
|
||||
private readonly BinaryReader _reader;
|
||||
private readonly List<ContainerContext> _stack;
|
||||
|
||||
private byte[] _byteBuffer;
|
||||
private char[] _charBuffer;
|
||||
|
||||
private BsonType _currentElementType;
|
||||
private BsonReaderState _bsonReaderState;
|
||||
private ContainerContext _currentContext;
|
||||
|
||||
private bool _readRootValueAsArray;
|
||||
private bool _jsonNet35BinaryCompatibility;
|
||||
private DateTimeKind _dateTimeKindHandling;
|
||||
|
||||
private enum BsonReaderState
|
||||
{
|
||||
Normal = 0,
|
||||
ReferenceStart = 1,
|
||||
ReferenceRef = 2,
|
||||
ReferenceId = 3,
|
||||
CodeWScopeStart = 4,
|
||||
CodeWScopeCode = 5,
|
||||
CodeWScopeScope = 6,
|
||||
CodeWScopeScopeObject = 7,
|
||||
CodeWScopeScopeEnd = 8
|
||||
}
|
||||
|
||||
private class ContainerContext
|
||||
{
|
||||
public readonly BsonType Type;
|
||||
public int Length;
|
||||
public int Position;
|
||||
|
||||
public ContainerContext(BsonType type)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether binary data reading should be compatible with incorrect Json.NET 3.5 written binary.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if binary data reading will be compatible with incorrect Json.NET 3.5 written binary; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
[Obsolete("JsonNet35BinaryCompatibility will be removed in a future version of Json.NET.")]
|
||||
public bool JsonNet35BinaryCompatibility
|
||||
{
|
||||
get => this._jsonNet35BinaryCompatibility;
|
||||
set => this._jsonNet35BinaryCompatibility = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the root object will be read as a JSON array.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the root object will be read as a JSON array; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool ReadRootValueAsArray
|
||||
{
|
||||
get => this._readRootValueAsArray;
|
||||
set => this._readRootValueAsArray = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.
|
||||
/// </summary>
|
||||
/// <value>The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</value>
|
||||
public DateTimeKind DateTimeKindHandling
|
||||
{
|
||||
get => this._dateTimeKindHandling;
|
||||
set => this._dateTimeKindHandling = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
|
||||
public BsonReader(Stream stream)
|
||||
: this(stream, false, DateTimeKind.Local)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
|
||||
public BsonReader(BinaryReader reader)
|
||||
: this(reader, false, DateTimeKind.Local)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> containing the BSON data to read.</param>
|
||||
/// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
|
||||
/// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
|
||||
public BsonReader(Stream stream, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(stream, nameof(stream));
|
||||
this._reader = new BinaryReader(stream);
|
||||
this._stack = new List<ContainerContext>();
|
||||
this._readRootValueAsArray = readRootValueAsArray;
|
||||
this._dateTimeKindHandling = dateTimeKindHandling;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonReader"/> class.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="BinaryReader"/> containing the BSON data to read.</param>
|
||||
/// <param name="readRootValueAsArray">if set to <c>true</c> the root object will be read as a JSON array.</param>
|
||||
/// <param name="dateTimeKindHandling">The <see cref="DateTimeKind" /> used when reading <see cref="DateTime"/> values from BSON.</param>
|
||||
public BsonReader(BinaryReader reader, bool readRootValueAsArray, DateTimeKind dateTimeKindHandling)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||||
this._reader = reader;
|
||||
this._stack = new List<ContainerContext>();
|
||||
this._readRootValueAsArray = readRootValueAsArray;
|
||||
this._dateTimeKindHandling = dateTimeKindHandling;
|
||||
}
|
||||
|
||||
private string ReadElement()
|
||||
{
|
||||
this._currentElementType = this.ReadType();
|
||||
string elementName = this.ReadString();
|
||||
return elementName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next JSON token from the underlying <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the next token was read successfully; <c>false</c> if there are no more tokens to read.
|
||||
/// </returns>
|
||||
public override bool Read()
|
||||
{
|
||||
try
|
||||
{
|
||||
bool success;
|
||||
|
||||
switch (this._bsonReaderState)
|
||||
{
|
||||
case BsonReaderState.Normal:
|
||||
success = this.ReadNormal();
|
||||
break;
|
||||
|
||||
case BsonReaderState.ReferenceStart:
|
||||
case BsonReaderState.ReferenceRef:
|
||||
case BsonReaderState.ReferenceId:
|
||||
success = this.ReadReference();
|
||||
break;
|
||||
|
||||
case BsonReaderState.CodeWScopeStart:
|
||||
case BsonReaderState.CodeWScopeCode:
|
||||
case BsonReaderState.CodeWScopeScope:
|
||||
case BsonReaderState.CodeWScopeScopeObject:
|
||||
case BsonReaderState.CodeWScopeScopeEnd:
|
||||
success = this.ReadCodeWScope();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw JsonReaderException.Create(this, "Unexpected state: {0}".FormatWith(CultureInfo.InvariantCulture, this._bsonReaderState));
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
this.SetToken(JsonToken.None);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
this.SetToken(JsonToken.None);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the reader's state to <see cref="JsonReader.State.Closed"/>.
|
||||
/// If <see cref="JsonReader.CloseInput"/> is set to <c>true</c>, the underlying <see cref="Stream"/> is also closed.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
if (this.CloseInput)
|
||||
{
|
||||
#if HAVE_STREAM_READER_WRITER_CLOSE
|
||||
_reader?.Close();
|
||||
#else
|
||||
this._reader?.Dispose();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadCodeWScope()
|
||||
{
|
||||
switch (this._bsonReaderState)
|
||||
{
|
||||
case BsonReaderState.CodeWScopeStart:
|
||||
this.SetToken(JsonToken.PropertyName, "$code");
|
||||
this._bsonReaderState = BsonReaderState.CodeWScopeCode;
|
||||
return true;
|
||||
|
||||
case BsonReaderState.CodeWScopeCode:
|
||||
// total CodeWScope size - not used
|
||||
this.ReadInt32();
|
||||
|
||||
this.SetToken(JsonToken.String, this.ReadLengthString());
|
||||
this._bsonReaderState = BsonReaderState.CodeWScopeScope;
|
||||
return true;
|
||||
|
||||
case BsonReaderState.CodeWScopeScope:
|
||||
if (this.CurrentState == State.PostValue)
|
||||
{
|
||||
this.SetToken(JsonToken.PropertyName, "$scope");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetToken(JsonToken.StartObject);
|
||||
this._bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
|
||||
|
||||
ContainerContext newContext = new ContainerContext(BsonType.Object);
|
||||
this.PushContext(newContext);
|
||||
newContext.Length = this.ReadInt32();
|
||||
|
||||
return true;
|
||||
}
|
||||
case BsonReaderState.CodeWScopeScopeObject:
|
||||
bool result = this.ReadNormal();
|
||||
if (result && this.TokenType == JsonToken.EndObject)
|
||||
{
|
||||
this._bsonReaderState = BsonReaderState.CodeWScopeScopeEnd;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
case BsonReaderState.CodeWScopeScopeEnd:
|
||||
this.SetToken(JsonToken.EndObject);
|
||||
this._bsonReaderState = BsonReaderState.Normal;
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadReference()
|
||||
{
|
||||
switch (this.CurrentState)
|
||||
{
|
||||
case State.ObjectStart:
|
||||
{
|
||||
this.SetToken(JsonToken.PropertyName, JsonTypeReflector.RefPropertyName);
|
||||
this._bsonReaderState = BsonReaderState.ReferenceRef;
|
||||
return true;
|
||||
}
|
||||
case State.Property:
|
||||
{
|
||||
if (this._bsonReaderState == BsonReaderState.ReferenceRef)
|
||||
{
|
||||
this.SetToken(JsonToken.String, this.ReadLengthString());
|
||||
return true;
|
||||
}
|
||||
else if (this._bsonReaderState == BsonReaderState.ReferenceId)
|
||||
{
|
||||
this.SetToken(JsonToken.Bytes, this.ReadBytes(12));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + this._bsonReaderState);
|
||||
}
|
||||
}
|
||||
case State.PostValue:
|
||||
{
|
||||
if (this._bsonReaderState == BsonReaderState.ReferenceRef)
|
||||
{
|
||||
this.SetToken(JsonToken.PropertyName, JsonTypeReflector.IdPropertyName);
|
||||
this._bsonReaderState = BsonReaderState.ReferenceId;
|
||||
return true;
|
||||
}
|
||||
else if (this._bsonReaderState == BsonReaderState.ReferenceId)
|
||||
{
|
||||
this.SetToken(JsonToken.EndObject);
|
||||
this._bsonReaderState = BsonReaderState.Normal;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + this._bsonReaderState);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw JsonReaderException.Create(this, "Unexpected state when reading BSON reference: " + this.CurrentState);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadNormal()
|
||||
{
|
||||
switch (this.CurrentState)
|
||||
{
|
||||
case State.Start:
|
||||
{
|
||||
JsonToken token = (!this._readRootValueAsArray) ? JsonToken.StartObject : JsonToken.StartArray;
|
||||
BsonType type = (!this._readRootValueAsArray) ? BsonType.Object : BsonType.Array;
|
||||
|
||||
this.SetToken(token);
|
||||
ContainerContext newContext = new ContainerContext(type);
|
||||
this.PushContext(newContext);
|
||||
newContext.Length = this.ReadInt32();
|
||||
return true;
|
||||
}
|
||||
case State.Complete:
|
||||
case State.Closed:
|
||||
return false;
|
||||
|
||||
case State.Property:
|
||||
{
|
||||
this.ReadType(this._currentElementType);
|
||||
return true;
|
||||
}
|
||||
case State.ObjectStart:
|
||||
case State.ArrayStart:
|
||||
case State.PostValue:
|
||||
ContainerContext context = this._currentContext;
|
||||
if (context == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int lengthMinusEnd = context.Length - 1;
|
||||
|
||||
if (context.Position < lengthMinusEnd)
|
||||
{
|
||||
if (context.Type == BsonType.Array)
|
||||
{
|
||||
this.ReadElement();
|
||||
this.ReadType(this._currentElementType);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetToken(JsonToken.PropertyName, this.ReadElement());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (context.Position == lengthMinusEnd)
|
||||
{
|
||||
if (this.ReadByte() != 0)
|
||||
{
|
||||
throw JsonReaderException.Create(this, "Unexpected end of object byte value.");
|
||||
}
|
||||
|
||||
this.PopContext();
|
||||
if (this._currentContext != null)
|
||||
{
|
||||
this.MovePosition(context.Length);
|
||||
}
|
||||
|
||||
JsonToken endToken = (context.Type == BsonType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
|
||||
this.SetToken(endToken);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonReaderException.Create(this, "Read past end of current container context.");
|
||||
}
|
||||
case State.ConstructorStart:
|
||||
break;
|
||||
|
||||
case State.Constructor:
|
||||
break;
|
||||
|
||||
case State.Error:
|
||||
break;
|
||||
|
||||
case State.Finished:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PopContext()
|
||||
{
|
||||
this._stack.RemoveAt(this._stack.Count - 1);
|
||||
if (this._stack.Count == 0)
|
||||
{
|
||||
this._currentContext = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._currentContext = this._stack[this._stack.Count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
private void PushContext(ContainerContext newContext)
|
||||
{
|
||||
this._stack.Add(newContext);
|
||||
this._currentContext = newContext;
|
||||
}
|
||||
|
||||
private byte ReadByte()
|
||||
{
|
||||
this.MovePosition(1);
|
||||
return this._reader.ReadByte();
|
||||
}
|
||||
|
||||
private void ReadType(BsonType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BsonType.Number:
|
||||
double d = this.ReadDouble();
|
||||
|
||||
if (this._floatParseHandling == FloatParseHandling.Decimal)
|
||||
{
|
||||
this.SetToken(JsonToken.Float, Convert.ToDecimal(d, CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetToken(JsonToken.Float, d);
|
||||
}
|
||||
break;
|
||||
|
||||
case BsonType.String:
|
||||
case BsonType.Symbol:
|
||||
this.SetToken(JsonToken.String, this.ReadLengthString());
|
||||
break;
|
||||
|
||||
case BsonType.Object:
|
||||
{
|
||||
this.SetToken(JsonToken.StartObject);
|
||||
|
||||
ContainerContext newContext = new ContainerContext(BsonType.Object);
|
||||
this.PushContext(newContext);
|
||||
newContext.Length = this.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case BsonType.Array:
|
||||
{
|
||||
this.SetToken(JsonToken.StartArray);
|
||||
|
||||
ContainerContext newContext = new ContainerContext(BsonType.Array);
|
||||
this.PushContext(newContext);
|
||||
newContext.Length = this.ReadInt32();
|
||||
break;
|
||||
}
|
||||
case BsonType.Binary:
|
||||
BsonBinaryType binaryType;
|
||||
byte[] data = this.ReadBinary(out binaryType);
|
||||
|
||||
object value = (binaryType != BsonBinaryType.Uuid)
|
||||
? data
|
||||
: new Guid(data);
|
||||
|
||||
this.SetToken(JsonToken.Bytes, value);
|
||||
break;
|
||||
|
||||
case BsonType.Undefined:
|
||||
this.SetToken(JsonToken.Undefined);
|
||||
break;
|
||||
|
||||
case BsonType.Oid:
|
||||
byte[] oid = this.ReadBytes(12);
|
||||
this.SetToken(JsonToken.Bytes, oid);
|
||||
break;
|
||||
|
||||
case BsonType.Boolean:
|
||||
bool b = Convert.ToBoolean(this.ReadByte());
|
||||
this.SetToken(JsonToken.Boolean, b);
|
||||
break;
|
||||
|
||||
case BsonType.Date:
|
||||
long ticks = this.ReadInt64();
|
||||
DateTime utcDateTime = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks);
|
||||
|
||||
DateTime dateTime;
|
||||
switch (this.DateTimeKindHandling)
|
||||
{
|
||||
case DateTimeKind.Unspecified:
|
||||
dateTime = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Unspecified);
|
||||
break;
|
||||
|
||||
case DateTimeKind.Local:
|
||||
dateTime = utcDateTime.ToLocalTime();
|
||||
break;
|
||||
|
||||
default:
|
||||
dateTime = utcDateTime;
|
||||
break;
|
||||
}
|
||||
|
||||
this.SetToken(JsonToken.Date, dateTime);
|
||||
break;
|
||||
|
||||
case BsonType.Null:
|
||||
this.SetToken(JsonToken.Null);
|
||||
break;
|
||||
|
||||
case BsonType.Regex:
|
||||
string expression = this.ReadString();
|
||||
string modifiers = this.ReadString();
|
||||
|
||||
string regex = @"/" + expression + @"/" + modifiers;
|
||||
this.SetToken(JsonToken.String, regex);
|
||||
break;
|
||||
|
||||
case BsonType.Reference:
|
||||
this.SetToken(JsonToken.StartObject);
|
||||
this._bsonReaderState = BsonReaderState.ReferenceStart;
|
||||
break;
|
||||
|
||||
case BsonType.Code:
|
||||
this.SetToken(JsonToken.String, this.ReadLengthString());
|
||||
break;
|
||||
|
||||
case BsonType.CodeWScope:
|
||||
this.SetToken(JsonToken.StartObject);
|
||||
this._bsonReaderState = BsonReaderState.CodeWScopeStart;
|
||||
break;
|
||||
|
||||
case BsonType.Integer:
|
||||
this.SetToken(JsonToken.Integer, (long)this.ReadInt32());
|
||||
break;
|
||||
|
||||
case BsonType.TimeStamp:
|
||||
case BsonType.Long:
|
||||
this.SetToken(JsonToken.Integer, this.ReadInt64());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type), "Unexpected BsonType value: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ReadBinary(out BsonBinaryType binaryType)
|
||||
{
|
||||
int dataLength = this.ReadInt32();
|
||||
|
||||
binaryType = (BsonBinaryType)this.ReadByte();
|
||||
|
||||
#pragma warning disable 612,618
|
||||
// the old binary type has the data length repeated in the data for some reason
|
||||
if (binaryType == BsonBinaryType.BinaryOld && !this._jsonNet35BinaryCompatibility)
|
||||
{
|
||||
dataLength = this.ReadInt32();
|
||||
}
|
||||
#pragma warning restore 612,618
|
||||
|
||||
return this.ReadBytes(dataLength);
|
||||
}
|
||||
|
||||
private string ReadString()
|
||||
{
|
||||
this.EnsureBuffers();
|
||||
|
||||
StringBuilder builder = null;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
// used in case of left over multibyte characters in the buffer
|
||||
int offset = 0;
|
||||
while (true)
|
||||
{
|
||||
int count = offset;
|
||||
byte b;
|
||||
while (count < MaxCharBytesSize && (b = this._reader.ReadByte()) > 0)
|
||||
{
|
||||
this._byteBuffer[count++] = b;
|
||||
}
|
||||
int byteCount = count - offset;
|
||||
totalBytesRead += byteCount;
|
||||
|
||||
if (count < MaxCharBytesSize && builder == null)
|
||||
{
|
||||
// pref optimization to avoid reading into a string builder
|
||||
// if string is smaller than the buffer then return it directly
|
||||
int length = Encoding.UTF8.GetChars(this._byteBuffer, 0, byteCount, this._charBuffer, 0);
|
||||
|
||||
this.MovePosition(totalBytesRead + 1);
|
||||
return new string(this._charBuffer, 0, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate the index of the end of the last full character in the buffer
|
||||
int lastFullCharStop = this.GetLastFullCharStop(count - 1);
|
||||
|
||||
int charCount = Encoding.UTF8.GetChars(this._byteBuffer, 0, lastFullCharStop + 1, this._charBuffer, 0);
|
||||
|
||||
if (builder == null)
|
||||
{
|
||||
builder = new StringBuilder(MaxCharBytesSize * 2);
|
||||
}
|
||||
|
||||
builder.Append(this._charBuffer, 0, charCount);
|
||||
|
||||
if (lastFullCharStop < byteCount - 1)
|
||||
{
|
||||
offset = byteCount - lastFullCharStop - 1;
|
||||
// copy left over multi byte characters to beginning of buffer for next iteration
|
||||
Array.Copy(this._byteBuffer, lastFullCharStop + 1, this._byteBuffer, 0, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reached end of string
|
||||
if (count < MaxCharBytesSize)
|
||||
{
|
||||
this.MovePosition(totalBytesRead + 1);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadLengthString()
|
||||
{
|
||||
int length = this.ReadInt32();
|
||||
|
||||
this.MovePosition(length);
|
||||
|
||||
string s = this.GetString(length - 1);
|
||||
this._reader.ReadByte();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private string GetString(int length)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
this.EnsureBuffers();
|
||||
|
||||
StringBuilder builder = null;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
|
||||
// used in case of left over multibyte characters in the buffer
|
||||
int offset = 0;
|
||||
do
|
||||
{
|
||||
int count = ((length - totalBytesRead) > MaxCharBytesSize - offset)
|
||||
? MaxCharBytesSize - offset
|
||||
: length - totalBytesRead;
|
||||
|
||||
int byteCount = this._reader.Read(this._byteBuffer, offset, count);
|
||||
|
||||
if (byteCount == 0)
|
||||
{
|
||||
throw new EndOfStreamException("Unable to read beyond the end of the stream.");
|
||||
}
|
||||
|
||||
totalBytesRead += byteCount;
|
||||
|
||||
// Above, byteCount is how many bytes we read this time.
|
||||
// Below, byteCount is how many bytes are in the _byteBuffer.
|
||||
byteCount += offset;
|
||||
|
||||
if (byteCount == length)
|
||||
{
|
||||
// pref optimization to avoid reading into a string builder
|
||||
// first iteration and all bytes read then return string directly
|
||||
int charCount = Encoding.UTF8.GetChars(this._byteBuffer, 0, byteCount, this._charBuffer, 0);
|
||||
return new string(this._charBuffer, 0, charCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastFullCharStop = this.GetLastFullCharStop(byteCount - 1);
|
||||
|
||||
if (builder == null)
|
||||
{
|
||||
builder = new StringBuilder(length);
|
||||
}
|
||||
|
||||
int charCount = Encoding.UTF8.GetChars(this._byteBuffer, 0, lastFullCharStop + 1, this._charBuffer, 0);
|
||||
builder.Append(this._charBuffer, 0, charCount);
|
||||
|
||||
if (lastFullCharStop < byteCount - 1)
|
||||
{
|
||||
offset = byteCount - lastFullCharStop - 1;
|
||||
// copy left over multi byte characters to beginning of buffer for next iteration
|
||||
Array.Copy(this._byteBuffer, lastFullCharStop + 1, this._byteBuffer, 0, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
} while (totalBytesRead < length);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private int GetLastFullCharStop(int start)
|
||||
{
|
||||
int lookbackPos = start;
|
||||
int bis = 0;
|
||||
while (lookbackPos >= 0)
|
||||
{
|
||||
bis = this.BytesInSequence(this._byteBuffer[lookbackPos]);
|
||||
if (bis == 0)
|
||||
{
|
||||
lookbackPos--;
|
||||
continue;
|
||||
}
|
||||
else if (bis == 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
lookbackPos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bis == start - lookbackPos)
|
||||
{
|
||||
//Full character.
|
||||
return start;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lookbackPos;
|
||||
}
|
||||
}
|
||||
|
||||
private int BytesInSequence(byte b)
|
||||
{
|
||||
if (b <= SeqRange1[1])
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (b >= SeqRange2[0] && b <= SeqRange2[1])
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
if (b >= SeqRange3[0] && b <= SeqRange3[1])
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (b >= SeqRange4[0] && b <= SeqRange4[1])
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void EnsureBuffers()
|
||||
{
|
||||
if (this._byteBuffer == null)
|
||||
{
|
||||
this._byteBuffer = new byte[MaxCharBytesSize];
|
||||
}
|
||||
if (this._charBuffer == null)
|
||||
{
|
||||
int charBufferSize = Encoding.UTF8.GetMaxCharCount(MaxCharBytesSize);
|
||||
this._charBuffer = new char[charBufferSize];
|
||||
}
|
||||
}
|
||||
|
||||
private double ReadDouble()
|
||||
{
|
||||
this.MovePosition(8);
|
||||
return this._reader.ReadDouble();
|
||||
}
|
||||
|
||||
private int ReadInt32()
|
||||
{
|
||||
this.MovePosition(4);
|
||||
return this._reader.ReadInt32();
|
||||
}
|
||||
|
||||
private long ReadInt64()
|
||||
{
|
||||
this.MovePosition(8);
|
||||
return this._reader.ReadInt64();
|
||||
}
|
||||
|
||||
private BsonType ReadType()
|
||||
{
|
||||
this.MovePosition(1);
|
||||
return (BsonType)this._reader.ReadSByte();
|
||||
}
|
||||
|
||||
private void MovePosition(int count)
|
||||
{
|
||||
this._currentContext.Position += count;
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(int count)
|
||||
{
|
||||
this.MovePosition(count);
|
||||
return this._reader.ReadBytes(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
181
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonToken.cs
Normal file
181
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonToken.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
internal abstract class BsonToken
|
||||
{
|
||||
public abstract BsonType Type { get; }
|
||||
public BsonToken Parent { get; set; }
|
||||
public int CalculatedSize { get; set; }
|
||||
}
|
||||
|
||||
internal class BsonObject : BsonToken, IEnumerable<BsonProperty>
|
||||
{
|
||||
private readonly List<BsonProperty> _children = new List<BsonProperty>();
|
||||
|
||||
public void Add(string name, BsonToken token)
|
||||
{
|
||||
this._children.Add(new BsonProperty { Name = new BsonString(name, false), Value = token });
|
||||
token.Parent = this;
|
||||
}
|
||||
|
||||
public override BsonType Type => BsonType.Object;
|
||||
|
||||
public IEnumerator<BsonProperty> GetEnumerator()
|
||||
{
|
||||
return this._children.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
internal class BsonArray : BsonToken, IEnumerable<BsonToken>
|
||||
{
|
||||
private readonly List<BsonToken> _children = new List<BsonToken>();
|
||||
|
||||
public void Add(BsonToken token)
|
||||
{
|
||||
this._children.Add(token);
|
||||
token.Parent = this;
|
||||
}
|
||||
|
||||
public override BsonType Type => BsonType.Array;
|
||||
|
||||
public IEnumerator<BsonToken> GetEnumerator()
|
||||
{
|
||||
return this._children.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
internal class BsonEmpty : BsonToken
|
||||
{
|
||||
public static readonly BsonToken Null = new BsonEmpty(BsonType.Null);
|
||||
public static readonly BsonToken Undefined = new BsonEmpty(BsonType.Undefined);
|
||||
|
||||
private BsonEmpty(BsonType type)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
public override BsonType Type { get; }
|
||||
}
|
||||
|
||||
internal class BsonValue : BsonToken
|
||||
{
|
||||
private readonly object _value;
|
||||
private readonly BsonType _type;
|
||||
|
||||
public BsonValue(object value, BsonType type)
|
||||
{
|
||||
this._value = value;
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
public object Value => this._value;
|
||||
|
||||
public override BsonType Type => this._type;
|
||||
}
|
||||
|
||||
internal class BsonBoolean : BsonValue
|
||||
{
|
||||
public static readonly BsonBoolean False = new BsonBoolean(false);
|
||||
public static readonly BsonBoolean True = new BsonBoolean(true);
|
||||
|
||||
private BsonBoolean(bool value)
|
||||
: base(value, BsonType.Boolean)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class BsonString : BsonValue
|
||||
{
|
||||
public int ByteCount { get; set; }
|
||||
public bool IncludeLength { get; }
|
||||
|
||||
public BsonString(object value, bool includeLength)
|
||||
: base(value, BsonType.String)
|
||||
{
|
||||
this.IncludeLength = includeLength;
|
||||
}
|
||||
}
|
||||
|
||||
internal class BsonBinary : BsonValue
|
||||
{
|
||||
public BsonBinaryType BinaryType { get; set; }
|
||||
|
||||
public BsonBinary(byte[] value, BsonBinaryType binaryType)
|
||||
: base(value, BsonType.Binary)
|
||||
{
|
||||
this.BinaryType = binaryType;
|
||||
}
|
||||
}
|
||||
|
||||
internal class BsonRegex : BsonToken
|
||||
{
|
||||
public BsonString Pattern { get; set; }
|
||||
public BsonString Options { get; set; }
|
||||
|
||||
public BsonRegex(string pattern, string options)
|
||||
{
|
||||
this.Pattern = new BsonString(pattern, false);
|
||||
this.Options = new BsonString(options, false);
|
||||
}
|
||||
|
||||
public override BsonType Type => BsonType.Regex;
|
||||
}
|
||||
|
||||
internal class BsonProperty
|
||||
{
|
||||
public BsonString Name { get; set; }
|
||||
public BsonToken Value { get; set; }
|
||||
}
|
||||
}
|
||||
66
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonType.cs
Normal file
66
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonType.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
internal enum BsonType : sbyte
|
||||
{
|
||||
Number = 1,
|
||||
String = 2,
|
||||
Object = 3,
|
||||
Array = 4,
|
||||
Binary = 5,
|
||||
Undefined = 6,
|
||||
Oid = 7,
|
||||
Boolean = 8,
|
||||
Date = 9,
|
||||
Null = 10,
|
||||
Regex = 11,
|
||||
Reference = 12,
|
||||
Code = 13,
|
||||
Symbol = 14,
|
||||
CodeWScope = 15,
|
||||
Integer = 16,
|
||||
TimeStamp = 17,
|
||||
Long = 18,
|
||||
MinKey = -1,
|
||||
MaxKey = 127
|
||||
}
|
||||
}
|
||||
553
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonWriter.cs
Normal file
553
RRQMCore/XREF/Newtonsoft.Json/Bson/BsonWriter.cs
Normal file
@@ -0,0 +1,553 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if HAVE_BIG_INTEGER
|
||||
using System.Numerics;
|
||||
#endif
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Bson
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a writer that provides a fast, non-cached, forward-only way of generating BSON data.
|
||||
/// </summary>
|
||||
[Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/RRQMCore.XREF.Newtonsoft.Json.Bson for more details.")]
|
||||
public class BsonWriter : JsonWriter
|
||||
{
|
||||
private readonly BsonBinaryWriter _writer;
|
||||
|
||||
private BsonToken _root;
|
||||
private BsonToken _parent;
|
||||
private string _propertyName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.
|
||||
/// When set to <see cref="DateTimeKind.Unspecified" /> no conversion will occur.
|
||||
/// </summary>
|
||||
/// <value>The <see cref="DateTimeKind" /> used when writing <see cref="DateTime"/> values to BSON.</value>
|
||||
public DateTimeKind DateTimeKindHandling
|
||||
{
|
||||
get => this._writer.DateTimeKindHandling;
|
||||
set => this._writer.DateTimeKindHandling = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonWriter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
|
||||
public BsonWriter(Stream stream)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(stream, nameof(stream));
|
||||
this._writer = new BsonBinaryWriter(new BinaryWriter(stream));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BsonWriter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="BinaryWriter"/> to write to.</param>
|
||||
public BsonWriter(BinaryWriter writer)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(writer, nameof(writer));
|
||||
this._writer = new BsonBinaryWriter(writer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes whatever is in the buffer to the underlying <see cref="Stream"/> and also flushes the underlying stream.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
this._writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the end.
|
||||
/// </summary>
|
||||
/// <param name="token">The token.</param>
|
||||
protected override void WriteEnd(JsonToken token)
|
||||
{
|
||||
base.WriteEnd(token);
|
||||
this.RemoveParent();
|
||||
|
||||
if (this.Top == 0)
|
||||
{
|
||||
this._writer.WriteToken(this._root);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a comment <c>/*...*/</c> containing the specified text.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to place inside the comment.</param>
|
||||
public override void WriteComment(string text)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Cannot write JSON comment as BSON.", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the start of a constructor with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the constructor.</param>
|
||||
public override void WriteStartConstructor(string name)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Cannot write JSON constructor as BSON.", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes raw JSON.
|
||||
/// </summary>
|
||||
/// <param name="json">The raw JSON to write.</param>
|
||||
public override void WriteRaw(string json)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes raw JSON where a value is expected and updates the writer's state.
|
||||
/// </summary>
|
||||
/// <param name="json">The raw JSON to write.</param>
|
||||
public override void WriteRawValue(string json)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Cannot write raw JSON as BSON.", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the beginning of a JSON array.
|
||||
/// </summary>
|
||||
public override void WriteStartArray()
|
||||
{
|
||||
base.WriteStartArray();
|
||||
|
||||
this.AddParent(new BsonArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the beginning of a JSON object.
|
||||
/// </summary>
|
||||
public override void WriteStartObject()
|
||||
{
|
||||
base.WriteStartObject();
|
||||
|
||||
this.AddParent(new BsonObject());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name of a name/value pair on a JSON object.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
public override void WritePropertyName(string name)
|
||||
{
|
||||
base.WritePropertyName(name);
|
||||
|
||||
this._propertyName = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes this writer.
|
||||
/// If <see cref="JsonWriter.CloseOutput"/> is set to <c>true</c>, the underlying <see cref="Stream"/> is also closed.
|
||||
/// If <see cref="JsonWriter.AutoCompleteOnClose"/> is set to <c>true</c>, the JSON is auto-completed.
|
||||
/// </summary>
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
if (this.CloseOutput)
|
||||
{
|
||||
this._writer?.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddParent(BsonToken container)
|
||||
{
|
||||
this.AddToken(container);
|
||||
this._parent = container;
|
||||
}
|
||||
|
||||
private void RemoveParent()
|
||||
{
|
||||
this._parent = this._parent.Parent;
|
||||
}
|
||||
|
||||
private void AddValue(object value, BsonType type)
|
||||
{
|
||||
this.AddToken(new BsonValue(value, type));
|
||||
}
|
||||
|
||||
internal void AddToken(BsonToken token)
|
||||
{
|
||||
if (this._parent != null)
|
||||
{
|
||||
BsonObject bo = this._parent as BsonObject;
|
||||
if (bo != null)
|
||||
{
|
||||
bo.Add(this._propertyName, token);
|
||||
this._propertyName = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
((BsonArray)this._parent).Add(token);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (token.Type != BsonType.Object && token.Type != BsonType.Array)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Error writing {0} value. BSON must start with an Object or Array.".FormatWith(CultureInfo.InvariantCulture, token.Type), null);
|
||||
}
|
||||
|
||||
this._parent = token;
|
||||
this._root = token;
|
||||
}
|
||||
}
|
||||
|
||||
#region WriteValue methods
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Object"/> value.
|
||||
/// An error will raised if the value cannot be written as a single JSON token.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Object"/> value to write.</param>
|
||||
public override void WriteValue(object value)
|
||||
{
|
||||
#if HAVE_BIG_INTEGER
|
||||
if (value is BigInteger)
|
||||
{
|
||||
SetWriteState(JsonToken.Integer, null);
|
||||
AddToken(new BsonBinary(((BigInteger)value).ToByteArray(), BsonBinaryType.Binary));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
base.WriteValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a null value.
|
||||
/// </summary>
|
||||
public override void WriteNull()
|
||||
{
|
||||
base.WriteNull();
|
||||
this.AddToken(BsonEmpty.Null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes an undefined value.
|
||||
/// </summary>
|
||||
public override void WriteUndefined()
|
||||
{
|
||||
base.WriteUndefined();
|
||||
this.AddToken(BsonEmpty.Undefined);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="String"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="String"/> value to write.</param>
|
||||
public override void WriteValue(string value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddToken(value == null ? BsonEmpty.Null : new BsonString(value, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int32"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int32"/> value to write.</param>
|
||||
public override void WriteValue(int value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt32"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
|
||||
|
||||
public override void WriteValue(uint value)
|
||||
{
|
||||
if (value > int.MaxValue)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values.", null);
|
||||
}
|
||||
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int64"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int64"/> value to write.</param>
|
||||
public override void WriteValue(long value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Long);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt64"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
|
||||
|
||||
public override void WriteValue(ulong value)
|
||||
{
|
||||
if (value > long.MaxValue)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "Value is too large to fit in a signed 64 bit integer. BSON does not support unsigned values.", null);
|
||||
}
|
||||
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Long);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Single"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Single"/> value to write.</param>
|
||||
public override void WriteValue(float value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Double"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Double"/> value to write.</param>
|
||||
public override void WriteValue(double value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Boolean"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
|
||||
public override void WriteValue(bool value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddToken(value ? BsonBoolean.True : BsonBoolean.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Int16"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Int16"/> value to write.</param>
|
||||
public override void WriteValue(short value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="UInt16"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
|
||||
|
||||
public override void WriteValue(ushort value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Char"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Char"/> value to write.</param>
|
||||
public override void WriteValue(char value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
string s = null;
|
||||
#if HAVE_CHAR_TO_STRING_WITH_CULTURE
|
||||
s = value.ToString(CultureInfo.InvariantCulture);
|
||||
#else
|
||||
s = value.ToString();
|
||||
#endif
|
||||
this.AddToken(new BsonString(s, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Byte"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Byte"/> value to write.</param>
|
||||
public override void WriteValue(byte value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="SByte"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="SByte"/> value to write.</param>
|
||||
|
||||
public override void WriteValue(sbyte value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Integer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Decimal"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
|
||||
public override void WriteValue(decimal value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddValue(value, BsonType.Number);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="DateTime"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
|
||||
public override void WriteValue(DateTime value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
value = DateTimeUtils.EnsureDateTime(value, this.DateTimeZoneHandling);
|
||||
this.AddValue(value, BsonType.Date);
|
||||
}
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
/// <summary>
|
||||
/// Writes a <see cref="DateTimeOffset"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
|
||||
public override void WriteValue(DateTimeOffset value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
AddValue(value, BsonType.Date);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Byte"/>[] value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
|
||||
public override void WriteValue(byte[] value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
base.WriteValue(value);
|
||||
this.AddToken(new BsonBinary(value, BsonBinaryType.Binary));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Guid"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Guid"/> value to write.</param>
|
||||
public override void WriteValue(Guid value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddToken(new BsonBinary(value.ToByteArray(), BsonBinaryType.Uuid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="TimeSpan"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
|
||||
public override void WriteValue(TimeSpan value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
this.AddToken(new BsonString(value.ToString(), true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Uri"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="Uri"/> value to write.</param>
|
||||
public override void WriteValue(Uri value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
this.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
base.WriteValue(value);
|
||||
this.AddToken(new BsonString(value.ToString(), true));
|
||||
}
|
||||
|
||||
#endregion WriteValue methods
|
||||
|
||||
/// <summary>
|
||||
/// Writes a <see cref="Byte"/>[] value that represents a BSON object id.
|
||||
/// </summary>
|
||||
/// <param name="value">The Object ID value to write.</param>
|
||||
public void WriteObjectId(byte[] value)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(value, nameof(value));
|
||||
|
||||
if (value.Length != 12)
|
||||
{
|
||||
throw JsonWriterException.Create(this, "An object id must be 12 bytes", null);
|
||||
}
|
||||
|
||||
// hack to update the writer state
|
||||
this.SetWriteState(JsonToken.Undefined, null);
|
||||
this.AddValue(value, BsonType.Oid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a BSON regex.
|
||||
/// </summary>
|
||||
/// <param name="pattern">The regex pattern.</param>
|
||||
/// <param name="options">The regex options.</param>
|
||||
public void WriteRegex(string pattern, string options)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(pattern, nameof(pattern));
|
||||
|
||||
// hack to update the writer state
|
||||
this.SetWriteState(JsonToken.Undefined, null);
|
||||
this.AddToken(new BsonRegex(pattern, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
58
RRQMCore/XREF/Newtonsoft.Json/ConstructorHandling.cs
Normal file
58
RRQMCore/XREF/Newtonsoft.Json/ConstructorHandling.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how constructors are used when initializing objects during deserialization by the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
public enum ConstructorHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// First attempt to use the public default constructor, then fall back to a single parameterized constructor, then to the non-public default constructor.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Json.NET will use a non-public default constructor before falling back to a parameterized constructor.
|
||||
/// </summary>
|
||||
AllowNonPublicDefaultConstructor = 1
|
||||
}
|
||||
}
|
||||
226
RRQMCore/XREF/Newtonsoft.Json/Converters/BinaryConverter.cs
Normal file
226
RRQMCore/XREF/Newtonsoft.Json/Converters/BinaryConverter.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_LINQ || HAVE_ADO_NET
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System.Collections.Generic;
|
||||
#if HAVE_ADO_NET
|
||||
using System.Data.SqlTypes;
|
||||
#endif
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a binary value to and from a base 64 string value.
|
||||
/// </summary>
|
||||
public class BinaryConverter : JsonConverter
|
||||
{
|
||||
#if HAVE_LINQ
|
||||
private const string BinaryTypeName = "System.Data.Linq.Binary";
|
||||
private const string BinaryToArrayName = "ToArray";
|
||||
private static ReflectionObject _reflectionObject;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = GetByteArray(value);
|
||||
|
||||
writer.WriteValue(data);
|
||||
}
|
||||
|
||||
private byte[] GetByteArray(object value)
|
||||
{
|
||||
#if HAVE_LINQ
|
||||
if (value.GetType().FullName == BinaryTypeName)
|
||||
{
|
||||
EnsureReflectionObject(value.GetType());
|
||||
return (byte[])_reflectionObject.GetValue(value, BinaryToArrayName);
|
||||
}
|
||||
#endif
|
||||
#if HAVE_ADO_NET
|
||||
if (value is SqlBinary binary)
|
||||
{
|
||||
return binary.Value;
|
||||
}
|
||||
#endif
|
||||
|
||||
throw new JsonSerializationException("Unexpected value type when writing binary: {0}".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
|
||||
}
|
||||
|
||||
#if HAVE_LINQ
|
||||
private static void EnsureReflectionObject(Type t)
|
||||
{
|
||||
if (_reflectionObject == null)
|
||||
{
|
||||
_reflectionObject = ReflectionObject.Create(t, t.GetConstructor(new[] { typeof(byte[]) }), BinaryToArrayName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!ReflectionUtils.IsNullable(objectType))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] data;
|
||||
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
data = ReadByteArray(reader);
|
||||
}
|
||||
else if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
// current token is already at base64 string
|
||||
// unable to call ReadAsBytes so do it the old fashion way
|
||||
string encodedData = reader.Value.ToString();
|
||||
data = Convert.FromBase64String(encodedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token parsing binary. Expected String or StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
Type t = (ReflectionUtils.IsNullableType(objectType))
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
|
||||
#if HAVE_LINQ
|
||||
if (t.FullName == BinaryTypeName)
|
||||
{
|
||||
EnsureReflectionObject(t);
|
||||
|
||||
return _reflectionObject.Creator(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_ADO_NET
|
||||
if (t == typeof(SqlBinary))
|
||||
{
|
||||
return new SqlBinary(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected object type when writing binary: {0}".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
private byte[] ReadByteArray(JsonReader reader)
|
||||
{
|
||||
List<byte> byteList = new List<byte>();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.Integer:
|
||||
byteList.Add(Convert.ToByte(reader.Value, CultureInfo.InvariantCulture));
|
||||
break;
|
||||
|
||||
case JsonToken.EndArray:
|
||||
return byteList.ToArray();
|
||||
|
||||
case JsonToken.Comment:
|
||||
// skip
|
||||
break;
|
||||
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when reading bytes: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading bytes.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
#if HAVE_LINQ
|
||||
if (objectType.FullName == BinaryTypeName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if HAVE_ADO_NET
|
||||
if (objectType == typeof(SqlBinary) || objectType == typeof(SqlBinary?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Bson;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="BsonObjectId"/> to and from JSON and BSON.
|
||||
/// </summary>
|
||||
[Obsolete("BSON reading and writing has been moved to its own package. See https://www.nuget.org/packages/RRQMCore.XREF.Newtonsoft.Json.Bson for more details.")]
|
||||
public class BsonObjectIdConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
BsonObjectId objectId = (BsonObjectId)value;
|
||||
|
||||
if (writer is BsonWriter bsonWriter)
|
||||
{
|
||||
bsonWriter.WriteObjectId(objectId.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValue(objectId.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.Bytes)
|
||||
{
|
||||
throw new JsonSerializationException("Expected Bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
byte[] value = (byte[])reader.Value;
|
||||
|
||||
return new BsonObjectId(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(BsonObjectId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a custom object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object type to convert.</typeparam>
|
||||
public abstract class CustomCreationConverter<T> : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
T value = this.Create(objectType);
|
||||
if (value == null)
|
||||
{
|
||||
throw new JsonSerializationException("No object created.");
|
||||
}
|
||||
|
||||
serializer.Populate(reader, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object which will then be populated by the serializer.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>The created object.</returns>
|
||||
public abstract T Create(Type objectType);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(T).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public override bool CanWrite => false;
|
||||
}
|
||||
}
|
||||
140
RRQMCore/XREF/Newtonsoft.Json/Converters/DataSetConverter.cs
Normal file
140
RRQMCore/XREF/Newtonsoft.Json/Converters/DataSetConverter.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_ADO_NET
|
||||
using System;
|
||||
using System.Data;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="DataSet"/> to and from JSON.
|
||||
/// </summary>
|
||||
public class DataSetConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
DataSet dataSet = (DataSet)value;
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
DataTableConverter converter = new DataTableConverter();
|
||||
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach (DataTable table in dataSet.Tables)
|
||||
{
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(table.TableName) : table.TableName);
|
||||
|
||||
converter.WriteJson(writer, table, serializer);
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// handle typed datasets
|
||||
DataSet ds = (objectType == typeof(DataSet))
|
||||
? new DataSet()
|
||||
: (DataSet)Activator.CreateInstance(objectType);
|
||||
|
||||
DataTableConverter converter = new DataTableConverter();
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
while (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
DataTable dt = ds.Tables[(string)reader.Value];
|
||||
bool exists = (dt != null);
|
||||
|
||||
dt = (DataTable)converter.ReadJson(reader, typeof(DataTable), dt, serializer);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
ds.Tables.Add(dt);
|
||||
}
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified value type.
|
||||
/// </summary>
|
||||
/// <param name="valueType">Type of the value.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type valueType)
|
||||
{
|
||||
return typeof(DataSet).IsAssignableFrom(valueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
271
RRQMCore/XREF/Newtonsoft.Json/Converters/DataTableConverter.cs
Normal file
271
RRQMCore/XREF/Newtonsoft.Json/Converters/DataTableConverter.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_ADO_NET
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Data;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="DataTable"/> to and from JSON.
|
||||
/// </summary>
|
||||
public class DataTableConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
DataTable table = (DataTable)value;
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
writer.WriteStartArray();
|
||||
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
foreach (DataColumn column in row.Table.Columns)
|
||||
{
|
||||
object columnValue = row[column];
|
||||
|
||||
if (serializer.NullValueHandling == NullValueHandling.Ignore && (columnValue == null || columnValue == DBNull.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(column.ColumnName) : column.ColumnName);
|
||||
serializer.Serialize(writer, columnValue);
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(existingValue is DataTable dt))
|
||||
{
|
||||
// handle typed datasets
|
||||
dt = (objectType == typeof(DataTable))
|
||||
? new DataTable()
|
||||
: (DataTable)Activator.CreateInstance(objectType);
|
||||
}
|
||||
|
||||
// DataTable is inside a DataSet
|
||||
// populate the name from the property name
|
||||
if (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
dt.TableName = (string)reader.Value;
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.TokenType != JsonToken.StartArray)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
CreateRow(reader, dt, serializer);
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
private static void CreateRow(JsonReader reader, DataTable dt, JsonSerializer serializer)
|
||||
{
|
||||
DataRow dr = dt.NewRow();
|
||||
reader.ReadAndAssert();
|
||||
|
||||
while (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
string columnName = (string)reader.Value;
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
DataColumn column = dt.Columns[columnName];
|
||||
if (column == null)
|
||||
{
|
||||
Type columnType = GetColumnDataType(reader);
|
||||
column = new DataColumn(columnName, columnType);
|
||||
dt.Columns.Add(column);
|
||||
}
|
||||
|
||||
if (column.DataType == typeof(DataTable))
|
||||
{
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
DataTable nestedDt = new DataTable();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
CreateRow(reader, nestedDt, serializer);
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
dr[columnName] = nestedDt;
|
||||
}
|
||||
else if (column.DataType.IsArray && column.DataType != typeof(byte[]))
|
||||
{
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
List<object> o = new List<object>();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
o.Add(reader.Value);
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
Array destinationArray = Array.CreateInstance(column.DataType.GetElementType(), o.Count);
|
||||
((IList)o).CopyTo(destinationArray, 0);
|
||||
|
||||
dr[columnName] = destinationArray;
|
||||
}
|
||||
else
|
||||
{
|
||||
object columnValue = (reader.Value != null)
|
||||
? serializer.Deserialize(reader, column.DataType) ?? DBNull.Value
|
||||
: DBNull.Value;
|
||||
|
||||
dr[columnName] = columnValue;
|
||||
}
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
dr.EndEdit();
|
||||
dt.Rows.Add(dr);
|
||||
}
|
||||
|
||||
private static Type GetColumnDataType(JsonReader reader)
|
||||
{
|
||||
JsonToken tokenType = reader.TokenType;
|
||||
|
||||
switch (tokenType)
|
||||
{
|
||||
case JsonToken.Integer:
|
||||
case JsonToken.Boolean:
|
||||
case JsonToken.Float:
|
||||
case JsonToken.String:
|
||||
case JsonToken.Date:
|
||||
case JsonToken.Bytes:
|
||||
return reader.ValueType;
|
||||
|
||||
case JsonToken.Null:
|
||||
case JsonToken.Undefined:
|
||||
return typeof(string);
|
||||
|
||||
case JsonToken.StartArray:
|
||||
reader.ReadAndAssert();
|
||||
if (reader.TokenType == JsonToken.StartObject)
|
||||
{
|
||||
return typeof(DataTable); // nested datatable
|
||||
}
|
||||
|
||||
Type arrayType = GetColumnDataType(reader);
|
||||
return arrayType.MakeArrayType();
|
||||
|
||||
default:
|
||||
throw JsonSerializationException.Create(reader, "Unexpected JSON token when reading DataTable: {0}".FormatWith(CultureInfo.InvariantCulture, tokenType));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified value type.
|
||||
/// </summary>
|
||||
/// <param name="valueType">Type of the value.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified value type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type valueType)
|
||||
{
|
||||
return typeof(DataTable).IsAssignableFrom(valueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for converting a <see cref="DateTime"/> to and from JSON.
|
||||
/// </summary>
|
||||
public abstract class DateTimeConverterBase : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
if (objectType == typeof(DateTime) || objectType == typeof(DateTime?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
if (objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_FSHARP_TYPES
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if !HAVE_LINQ
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
#endif
|
||||
using System.Reflection;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
using System.Globalization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a F# discriminated union type to and from JSON.
|
||||
/// </summary>
|
||||
public class DiscriminatedUnionConverter : JsonConverter
|
||||
{
|
||||
#region UnionDefinition
|
||||
|
||||
internal class Union
|
||||
{
|
||||
public List<UnionCase> Cases;
|
||||
public FSharpFunction TagReader { get; set; }
|
||||
}
|
||||
|
||||
internal class UnionCase
|
||||
{
|
||||
public int Tag;
|
||||
public string Name;
|
||||
public PropertyInfo[] Fields;
|
||||
public FSharpFunction FieldReader;
|
||||
public FSharpFunction Constructor;
|
||||
}
|
||||
|
||||
#endregion UnionDefinition
|
||||
|
||||
private const string CasePropertyName = "Case";
|
||||
private const string FieldsPropertyName = "Fields";
|
||||
|
||||
private static readonly ThreadSafeStore<Type, Union> UnionCache = new ThreadSafeStore<Type, Union>(CreateUnion);
|
||||
private static readonly ThreadSafeStore<Type, Type> UnionTypeLookupCache = new ThreadSafeStore<Type, Type>(CreateUnionTypeLookup);
|
||||
|
||||
private static Type CreateUnionTypeLookup(Type t)
|
||||
{
|
||||
// this lookup is because cases with fields are derived from union type
|
||||
// need to get declaring type to avoid duplicate Unions in cache
|
||||
|
||||
// hacky but I can't find an API to get the declaring type without GetUnionCases
|
||||
object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null);
|
||||
|
||||
object caseInfo = cases.First();
|
||||
|
||||
Type unionType = (Type)FSharpUtils.GetUnionCaseInfoDeclaringType(caseInfo);
|
||||
return unionType;
|
||||
}
|
||||
|
||||
private static Union CreateUnion(Type t)
|
||||
{
|
||||
Union u = new Union();
|
||||
|
||||
u.TagReader = (FSharpFunction)FSharpUtils.PreComputeUnionTagReader(null, t, null);
|
||||
u.Cases = new List<UnionCase>();
|
||||
|
||||
object[] cases = (object[])FSharpUtils.GetUnionCases(null, t, null);
|
||||
|
||||
foreach (object unionCaseInfo in cases)
|
||||
{
|
||||
UnionCase unionCase = new UnionCase();
|
||||
unionCase.Tag = (int)FSharpUtils.GetUnionCaseInfoTag(unionCaseInfo);
|
||||
unionCase.Name = (string)FSharpUtils.GetUnionCaseInfoName(unionCaseInfo);
|
||||
unionCase.Fields = (PropertyInfo[])FSharpUtils.GetUnionCaseInfoFields(unionCaseInfo);
|
||||
unionCase.FieldReader = (FSharpFunction)FSharpUtils.PreComputeUnionReader(null, unionCaseInfo, null);
|
||||
unionCase.Constructor = (FSharpFunction)FSharpUtils.PreComputeUnionConstructor(null, unionCaseInfo, null);
|
||||
|
||||
u.Cases.Add(unionCase);
|
||||
}
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
Type unionType = UnionTypeLookupCache.Get(value.GetType());
|
||||
Union union = UnionCache.Get(unionType);
|
||||
|
||||
int tag = (int)union.TagReader.Invoke(value);
|
||||
UnionCase caseInfo = union.Cases.Single(c => c.Tag == tag);
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(CasePropertyName) : CasePropertyName);
|
||||
writer.WriteValue(caseInfo.Name);
|
||||
if (caseInfo.Fields != null && caseInfo.Fields.Length > 0)
|
||||
{
|
||||
object[] fields = (object[])caseInfo.FieldReader.Invoke(value);
|
||||
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(FieldsPropertyName) : FieldsPropertyName);
|
||||
writer.WriteStartArray();
|
||||
foreach (object field in fields)
|
||||
{
|
||||
serializer.Serialize(writer, field);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
UnionCase caseInfo = null;
|
||||
string caseName = null;
|
||||
JArray fields = null;
|
||||
|
||||
// start object
|
||||
reader.ReadAndAssert();
|
||||
|
||||
while (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
string propertyName = reader.Value.ToString();
|
||||
if (string.Equals(propertyName, CasePropertyName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
|
||||
Union union = UnionCache.Get(objectType);
|
||||
|
||||
caseName = reader.Value.ToString();
|
||||
|
||||
caseInfo = union.Cases.SingleOrDefault(c => c.Name == caseName);
|
||||
|
||||
if (caseInfo == null)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "No union type found with the name '{0}'.".FormatWith(CultureInfo.InvariantCulture, caseName));
|
||||
}
|
||||
}
|
||||
else if (string.Equals(propertyName, FieldsPropertyName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
if (reader.TokenType != JsonToken.StartArray)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Union fields must been an array.");
|
||||
}
|
||||
|
||||
fields = (JArray)JToken.ReadFrom(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected property '{0}' found when reading union.".FormatWith(CultureInfo.InvariantCulture, propertyName));
|
||||
}
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
if (caseInfo == null)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "No '{0}' property with union name found.".FormatWith(CultureInfo.InvariantCulture, CasePropertyName));
|
||||
}
|
||||
|
||||
object[] typedFieldValues = new object[caseInfo.Fields.Length];
|
||||
|
||||
if (caseInfo.Fields.Length > 0 && fields == null)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "No '{0}' property with union fields found.".FormatWith(CultureInfo.InvariantCulture, FieldsPropertyName));
|
||||
}
|
||||
|
||||
if (fields != null)
|
||||
{
|
||||
if (caseInfo.Fields.Length != fields.Count)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "The number of field values does not match the number of properties defined by union '{0}'.".FormatWith(CultureInfo.InvariantCulture, caseName));
|
||||
}
|
||||
|
||||
for (int i = 0; i < fields.Count; i++)
|
||||
{
|
||||
JToken t = fields[i];
|
||||
PropertyInfo fieldProperty = caseInfo.Fields[i];
|
||||
|
||||
typedFieldValues[i] = t.ToObject(fieldProperty.PropertyType, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
object[] args = { typedFieldValues };
|
||||
|
||||
return caseInfo.Constructor.Invoke(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(objectType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// all fsharp objects have CompilationMappingAttribute
|
||||
// get the fsharp assembly from the attribute and initialize latebound methods
|
||||
object[] attributes;
|
||||
#if HAVE_FULL_REFLECTION
|
||||
attributes = objectType.GetCustomAttributes(true);
|
||||
#else
|
||||
attributes = objectType.GetTypeInfo().GetCustomAttributes(true).ToArray();
|
||||
#endif
|
||||
|
||||
bool isFSharpType = false;
|
||||
foreach (object attribute in attributes)
|
||||
{
|
||||
Type attributeType = attribute.GetType();
|
||||
if (attributeType.FullName == "Microsoft.FSharp.Core.CompilationMappingAttribute")
|
||||
{
|
||||
FSharpUtils.EnsureInitialized(attributeType.Assembly());
|
||||
|
||||
isFSharpType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFSharpType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)FSharpUtils.IsUnion(null, objectType, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,171 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_ENTITY_FRAMEWORK
|
||||
using System;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
using System.Globalization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an Entity Framework <see cref="T:System.Data.EntityKeyMember"/> to and from JSON.
|
||||
/// </summary>
|
||||
public class EntityKeyMemberConverter : JsonConverter
|
||||
{
|
||||
private const string EntityKeyMemberFullTypeName = "System.Data.EntityKeyMember";
|
||||
|
||||
private const string KeyPropertyName = "Key";
|
||||
private const string TypePropertyName = "Type";
|
||||
private const string ValuePropertyName = "Value";
|
||||
|
||||
private static ReflectionObject _reflectionObject;
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
EnsureReflectionObject(value.GetType());
|
||||
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
string keyName = (string)_reflectionObject.GetValue(value, KeyPropertyName);
|
||||
object keyValue = _reflectionObject.GetValue(value, ValuePropertyName);
|
||||
|
||||
Type keyValueType = keyValue?.GetType();
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyPropertyName) : KeyPropertyName);
|
||||
writer.WriteValue(keyName);
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(TypePropertyName) : TypePropertyName);
|
||||
writer.WriteValue(keyValueType?.FullName);
|
||||
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(ValuePropertyName) : ValuePropertyName);
|
||||
|
||||
if (keyValueType != null)
|
||||
{
|
||||
if (JsonSerializerInternalWriter.TryConvertToString(keyValue, keyValueType, out string valueJson))
|
||||
{
|
||||
writer.WriteValue(valueJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValue(keyValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteNull();
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private static void ReadAndAssertProperty(JsonReader reader, string propertyName)
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
|
||||
if (reader.TokenType != JsonToken.PropertyName || !string.Equals(reader.Value.ToString(), propertyName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new JsonSerializationException("Expected JSON property '{0}'.".FormatWith(CultureInfo.InvariantCulture, propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
EnsureReflectionObject(objectType);
|
||||
|
||||
object entityKeyMember = _reflectionObject.Creator();
|
||||
|
||||
ReadAndAssertProperty(reader, KeyPropertyName);
|
||||
reader.ReadAndAssert();
|
||||
_reflectionObject.SetValue(entityKeyMember, KeyPropertyName, reader.Value.ToString());
|
||||
|
||||
ReadAndAssertProperty(reader, TypePropertyName);
|
||||
reader.ReadAndAssert();
|
||||
string type = reader.Value.ToString();
|
||||
|
||||
Type t = Type.GetType(type);
|
||||
|
||||
ReadAndAssertProperty(reader, ValuePropertyName);
|
||||
reader.ReadAndAssert();
|
||||
_reflectionObject.SetValue(entityKeyMember, ValuePropertyName, serializer.Deserialize(reader, t));
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
return entityKeyMember;
|
||||
}
|
||||
|
||||
private static void EnsureReflectionObject(Type objectType)
|
||||
{
|
||||
if (_reflectionObject == null)
|
||||
{
|
||||
_reflectionObject = ReflectionObject.Create(objectType, KeyPropertyName, ValuePropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.AssignableToTypeName(EntityKeyMemberFullTypeName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
#if HAVE_DYNAMIC
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an <see cref="ExpandoObject"/> to and from JSON.
|
||||
/// </summary>
|
||||
public class ExpandoObjectConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
// can write is set to false
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
return ReadValue(reader);
|
||||
}
|
||||
|
||||
private object ReadValue(JsonReader reader)
|
||||
{
|
||||
if (!reader.MoveToContent())
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
|
||||
}
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.StartObject:
|
||||
return ReadObject(reader);
|
||||
|
||||
case JsonToken.StartArray:
|
||||
return ReadList(reader);
|
||||
|
||||
default:
|
||||
if (JsonTokenUtils.IsPrimitiveToken(reader.TokenType))
|
||||
{
|
||||
return reader.Value;
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when converting ExpandoObject: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
}
|
||||
|
||||
private object ReadList(JsonReader reader)
|
||||
{
|
||||
IList<object> list = new List<object>();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
|
||||
default:
|
||||
object v = ReadValue(reader);
|
||||
|
||||
list.Add(v);
|
||||
break;
|
||||
|
||||
case JsonToken.EndArray:
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
|
||||
}
|
||||
|
||||
private object ReadObject(JsonReader reader)
|
||||
{
|
||||
IDictionary<string, object> expandoObject = new ExpandoObject();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
string propertyName = reader.Value.ToString();
|
||||
|
||||
if (!reader.Read())
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
|
||||
}
|
||||
|
||||
object v = ReadValue(reader);
|
||||
|
||||
expandoObject[propertyName] = v;
|
||||
break;
|
||||
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
|
||||
case JsonToken.EndObject:
|
||||
return expandoObject;
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading ExpandoObject.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(ExpandoObject));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
209
RRQMCore/XREF/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
Normal file
209
RRQMCore/XREF/Newtonsoft.Json/Converters/IsoDateTimeConverter.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="DateTime"/> to and from the ISO 8601 date format (e.g. <c>"2008-04-12T12:53Z"</c>).
|
||||
/// </summary>
|
||||
public class IsoDateTimeConverter : DateTimeConverterBase
|
||||
{
|
||||
private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
|
||||
|
||||
private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind;
|
||||
private string _dateTimeFormat;
|
||||
private CultureInfo _culture;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date time styles used when converting a date to and from JSON.
|
||||
/// </summary>
|
||||
/// <value>The date time styles used when converting a date to and from JSON.</value>
|
||||
public DateTimeStyles DateTimeStyles
|
||||
{
|
||||
get => this._dateTimeStyles;
|
||||
set => this._dateTimeStyles = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date time format used when converting a date to and from JSON.
|
||||
/// </summary>
|
||||
/// <value>The date time format used when converting a date to and from JSON.</value>
|
||||
public string DateTimeFormat
|
||||
{
|
||||
get => this._dateTimeFormat ?? string.Empty;
|
||||
set => this._dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the culture used when converting a date to and from JSON.
|
||||
/// </summary>
|
||||
/// <value>The culture used when converting a date to and from JSON.</value>
|
||||
public CultureInfo Culture
|
||||
{
|
||||
get => this._culture ?? CultureInfo.CurrentCulture;
|
||||
set => this._culture = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
string text;
|
||||
|
||||
if (value is DateTime dateTime)
|
||||
{
|
||||
if ((this._dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
|
||||
|| (this._dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
|
||||
{
|
||||
dateTime = dateTime.ToUniversalTime();
|
||||
}
|
||||
|
||||
text = dateTime.ToString(this._dateTimeFormat ?? DefaultDateTimeFormat, this.Culture);
|
||||
}
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
else if (value is DateTimeOffset dateTimeOffset)
|
||||
{
|
||||
if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
|
||||
|| (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
|
||||
{
|
||||
dateTimeOffset = dateTimeOffset.ToUniversalTime();
|
||||
}
|
||||
|
||||
text = dateTimeOffset.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException("Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {0}.".FormatWith(CultureInfo.InvariantCulture, ReflectionUtils.GetObjectType(value)));
|
||||
}
|
||||
|
||||
writer.WriteValue(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
bool nullable = ReflectionUtils.IsNullableType(objectType);
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!nullable)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
Type t = (nullable)
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
#endif
|
||||
|
||||
if (reader.TokenType == JsonToken.Date)
|
||||
{
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
if (t == typeof(DateTimeOffset))
|
||||
{
|
||||
return (reader.Value is DateTimeOffset) ? reader.Value : new DateTimeOffset((DateTime)reader.Value);
|
||||
}
|
||||
|
||||
// converter is expected to return a DateTime
|
||||
if (reader.Value is DateTimeOffset offset)
|
||||
{
|
||||
return offset.DateTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
return reader.Value;
|
||||
}
|
||||
|
||||
if (reader.TokenType != JsonToken.String)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
string dateText = reader.Value.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(dateText) && nullable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
if (t == typeof(DateTimeOffset))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_dateTimeFormat))
|
||||
{
|
||||
return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!string.IsNullOrEmpty(this._dateTimeFormat))
|
||||
{
|
||||
return DateTime.ParseExact(dateText, this._dateTimeFormat, this.Culture, this._dateTimeStyles);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTime.Parse(dateText, this.Culture, this._dateTimeStyles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="DateTime"/> to and from a JavaScript <c>Date</c> constructor (e.g. <c>new Date(52231943)</c>).
|
||||
/// </summary>
|
||||
public class JavaScriptDateTimeConverter : DateTimeConverterBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
long ticks;
|
||||
|
||||
if (value is DateTime dateTime)
|
||||
{
|
||||
DateTime utcDateTime = dateTime.ToUniversalTime();
|
||||
ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTime);
|
||||
}
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
else if (value is DateTimeOffset dateTimeOffset)
|
||||
{
|
||||
DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime();
|
||||
ticks = DateTimeUtils.ConvertDateTimeToJavaScriptTicks(utcDateTimeOffset.UtcDateTime);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException("Expected date object value.");
|
||||
}
|
||||
|
||||
writer.WriteStartConstructor("Date");
|
||||
writer.WriteValue(ticks);
|
||||
writer.WriteEndConstructor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!ReflectionUtils.IsNullable(objectType))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reader.TokenType != JsonToken.StartConstructor || !string.Equals(reader.Value.ToString(), "Date", StringComparison.Ordinal))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing date. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value));
|
||||
}
|
||||
|
||||
reader.Read();
|
||||
|
||||
if (reader.TokenType != JsonToken.Integer)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
long ticks = (long)reader.Value;
|
||||
|
||||
DateTime d = DateTimeUtils.ConvertJavaScriptTicksToDateTime(ticks);
|
||||
|
||||
reader.Read();
|
||||
|
||||
if (reader.TokenType != JsonToken.EndConstructor)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected EndConstructor, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
Type t = (ReflectionUtils.IsNullableType(objectType))
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
if (t == typeof(DateTimeOffset))
|
||||
{
|
||||
return new DateTimeOffset(d);
|
||||
}
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="KeyValuePair{TKey,TValue}"/> to and from JSON.
|
||||
/// </summary>
|
||||
public class KeyValuePairConverter : JsonConverter
|
||||
{
|
||||
private const string KeyName = "Key";
|
||||
private const string ValueName = "Value";
|
||||
|
||||
private static readonly ThreadSafeStore<Type, ReflectionObject> ReflectionObjectPerType = new ThreadSafeStore<Type, ReflectionObject>(InitializeReflectionObject);
|
||||
|
||||
private static ReflectionObject InitializeReflectionObject(Type t)
|
||||
{
|
||||
IList<Type> genericArguments = t.GetGenericArguments();
|
||||
Type keyType = genericArguments[0];
|
||||
Type valueType = genericArguments[1];
|
||||
|
||||
return ReflectionObject.Create(t, t.GetConstructor(new[] { keyType, valueType }), KeyName, ValueName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
ReflectionObject reflectionObject = ReflectionObjectPerType.Get(value.GetType());
|
||||
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(KeyName) : KeyName);
|
||||
serializer.Serialize(writer, reflectionObject.GetValue(value, KeyName), reflectionObject.GetType(KeyName));
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(ValueName) : ValueName);
|
||||
serializer.Serialize(writer, reflectionObject.GetValue(value, ValueName), reflectionObject.GetType(ValueName));
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!ReflectionUtils.IsNullableType(objectType))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to KeyValuePair.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
object key = null;
|
||||
object value = null;
|
||||
|
||||
reader.ReadAndAssert();
|
||||
|
||||
Type t = ReflectionUtils.IsNullableType(objectType)
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
|
||||
ReflectionObject reflectionObject = ReflectionObjectPerType.Get(t);
|
||||
JsonContract keyContract = serializer.ContractResolver.ResolveContract(reflectionObject.GetType(KeyName));
|
||||
JsonContract valueContract = serializer.ContractResolver.ResolveContract(reflectionObject.GetType(ValueName));
|
||||
|
||||
while (reader.TokenType == JsonToken.PropertyName)
|
||||
{
|
||||
string propertyName = reader.Value.ToString();
|
||||
if (string.Equals(propertyName, KeyName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reader.ReadForTypeAndAssert(keyContract, false);
|
||||
|
||||
key = serializer.Deserialize(reader, keyContract.UnderlyingType);
|
||||
}
|
||||
else if (string.Equals(propertyName, ValueName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reader.ReadForTypeAndAssert(valueContract, false);
|
||||
|
||||
value = serializer.Deserialize(reader, valueContract.UnderlyingType);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Skip();
|
||||
}
|
||||
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
return reflectionObject.Creator(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
Type t = (ReflectionUtils.IsNullableType(objectType))
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
|
||||
if (t.IsValueType() && t.IsGenericType())
|
||||
{
|
||||
return (t.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
255
RRQMCore/XREF/Newtonsoft.Json/Converters/RegexConverter.cs
Normal file
255
RRQMCore/XREF/Newtonsoft.Json/Converters/RegexConverter.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Bson;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Serialization;
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Regex"/> to and from JSON and BSON.
|
||||
/// </summary>
|
||||
public class RegexConverter : JsonConverter
|
||||
{
|
||||
private const string PatternName = "Pattern";
|
||||
private const string OptionsName = "Options";
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
Regex regex = (Regex)value;
|
||||
|
||||
#pragma warning disable 618
|
||||
if (writer is BsonWriter bsonWriter)
|
||||
{
|
||||
this.WriteBson(bsonWriter, regex);
|
||||
}
|
||||
#pragma warning restore 618
|
||||
else
|
||||
{
|
||||
this.WriteJson(writer, regex, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasFlag(RegexOptions options, RegexOptions flag)
|
||||
{
|
||||
return ((options & flag) == flag);
|
||||
}
|
||||
|
||||
#pragma warning disable 618
|
||||
|
||||
private void WriteBson(BsonWriter writer, Regex regex)
|
||||
{
|
||||
// Regular expression - The first cstring is the regex pattern, the second
|
||||
// is the regex options string. Options are identified by characters, which
|
||||
// must be stored in alphabetical order. Valid options are 'i' for case
|
||||
// insensitive matching, 'm' for multiline matching, 'x' for verbose mode,
|
||||
// 'l' to make \w, \W, etc. locale dependent, 's' for dotall mode
|
||||
// ('.' matches everything), and 'u' to make \w, \W, etc. match unicode.
|
||||
|
||||
string options = null;
|
||||
|
||||
if (this.HasFlag(regex.Options, RegexOptions.IgnoreCase))
|
||||
{
|
||||
options += "i";
|
||||
}
|
||||
|
||||
if (this.HasFlag(regex.Options, RegexOptions.Multiline))
|
||||
{
|
||||
options += "m";
|
||||
}
|
||||
|
||||
if (this.HasFlag(regex.Options, RegexOptions.Singleline))
|
||||
{
|
||||
options += "s";
|
||||
}
|
||||
|
||||
options += "u";
|
||||
|
||||
if (this.HasFlag(regex.Options, RegexOptions.ExplicitCapture))
|
||||
{
|
||||
options += "x";
|
||||
}
|
||||
|
||||
writer.WriteRegex(regex.ToString(), options);
|
||||
}
|
||||
|
||||
#pragma warning restore 618
|
||||
|
||||
private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer)
|
||||
{
|
||||
DefaultContractResolver resolver = serializer.ContractResolver as DefaultContractResolver;
|
||||
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName);
|
||||
writer.WriteValue(regex.ToString());
|
||||
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(OptionsName) : OptionsName);
|
||||
serializer.Serialize(writer, regex.Options);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.StartObject:
|
||||
return this.ReadRegexObject(reader, serializer);
|
||||
|
||||
case JsonToken.String:
|
||||
return this.ReadRegexString(reader);
|
||||
|
||||
case JsonToken.Null:
|
||||
return null;
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token when reading Regex.");
|
||||
}
|
||||
|
||||
private object ReadRegexString(JsonReader reader)
|
||||
{
|
||||
string regexText = (string)reader.Value;
|
||||
|
||||
if (regexText.Length > 0 && regexText[0] == '/')
|
||||
{
|
||||
int patternOptionDelimiterIndex = regexText.LastIndexOf('/');
|
||||
|
||||
if (patternOptionDelimiterIndex > 0)
|
||||
{
|
||||
string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1);
|
||||
string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1);
|
||||
|
||||
RegexOptions options = MiscellaneousUtils.GetRegexOptions(optionsText);
|
||||
|
||||
return new Regex(patternText, options);
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Regex pattern must be enclosed by slashes.");
|
||||
}
|
||||
|
||||
private Regex ReadRegexObject(JsonReader reader, JsonSerializer serializer)
|
||||
{
|
||||
string pattern = null;
|
||||
RegexOptions? options = null;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.PropertyName:
|
||||
string propertyName = reader.Value.ToString();
|
||||
|
||||
if (!reader.Read())
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
|
||||
}
|
||||
|
||||
if (string.Equals(propertyName, PatternName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
pattern = (string)reader.Value;
|
||||
}
|
||||
else if (string.Equals(propertyName, OptionsName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
options = serializer.Deserialize<RegexOptions>(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Skip();
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonToken.Comment:
|
||||
break;
|
||||
|
||||
case JsonToken.EndObject:
|
||||
if (pattern == null)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Error deserializing Regex. No pattern found.");
|
||||
}
|
||||
|
||||
return new Regex(pattern, options ?? RegexOptions.None);
|
||||
}
|
||||
}
|
||||
|
||||
throw JsonSerializationException.Create(reader, "Unexpected end when reading Regex.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType.Name == nameof(Regex) && this.IsRegex(objectType);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private bool IsRegex(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(Regex));
|
||||
}
|
||||
}
|
||||
}
|
||||
194
RRQMCore/XREF/Newtonsoft.Json/Converters/StringEnumConverter.cs
Normal file
194
RRQMCore/XREF/Newtonsoft.Json/Converters/StringEnumConverter.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
#if !HAVE_LINQ
|
||||
#else
|
||||
using System.Linq;
|
||||
|
||||
#endif
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts an <see cref="Enum"/> to and from its name string value.
|
||||
/// </summary>
|
||||
public class StringEnumConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the written enum text should be camel case.
|
||||
/// The default value is <c>false</c>.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</value>
|
||||
public bool CamelCaseText { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether integer values are allowed when deserializing.
|
||||
/// The default value is <c>true</c>.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if integers are allowed when deserializing; otherwise, <c>false</c>.</value>
|
||||
public bool AllowIntegerValues { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||
/// </summary>
|
||||
public StringEnumConverter()
|
||||
{
|
||||
this.AllowIntegerValues = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StringEnumConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="camelCaseText"><c>true</c> if the written enum text will be camel case; otherwise, <c>false</c>.</param>
|
||||
public StringEnumConverter(bool camelCaseText)
|
||||
: this()
|
||||
{
|
||||
this.CamelCaseText = camelCaseText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
Enum e = (Enum)value;
|
||||
|
||||
if (!EnumUtils.TryToString(e.GetType(), value, this.CamelCaseText, out string enumName))
|
||||
{
|
||||
if (!this.AllowIntegerValues)
|
||||
{
|
||||
throw JsonSerializationException.Create(null, writer.ContainerPath, "Integer value {0} is not allowed.".FormatWith(CultureInfo.InvariantCulture, e.ToString("D")), null);
|
||||
}
|
||||
|
||||
// enum value has no name so write number
|
||||
writer.WriteValue(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValue(enumName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!ReflectionUtils.IsNullableType(objectType))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool isNullable = ReflectionUtils.IsNullableType(objectType);
|
||||
Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;
|
||||
|
||||
try
|
||||
{
|
||||
if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
string enumText = reader.Value.ToString();
|
||||
|
||||
if (enumText == string.Empty && isNullable)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return EnumUtils.ParseEnum(t, enumText, !this.AllowIntegerValues);
|
||||
}
|
||||
|
||||
if (reader.TokenType == JsonToken.Integer)
|
||||
{
|
||||
if (!this.AllowIntegerValues)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Integer value {0} is not allowed.".FormatWith(CultureInfo.InvariantCulture, reader.Value));
|
||||
}
|
||||
|
||||
return ConvertUtils.ConvertOrCast(reader.Value, CultureInfo.InvariantCulture, t);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(reader.Value), objectType), ex);
|
||||
}
|
||||
|
||||
// we don't actually expect to get here.
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token {0} when parsing enum.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
Type t = (ReflectionUtils.IsNullableType(objectType))
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
|
||||
return t.IsEnum();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="DateTime"/> to and from Unix epoch time
|
||||
/// </summary>
|
||||
public class UnixDateTimeConverter : DateTimeConverterBase
|
||||
{
|
||||
internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
long ticks;
|
||||
|
||||
if (value is DateTime dateTime)
|
||||
{
|
||||
ticks = (long)(dateTime.ToUniversalTime() - UnixEpoch).TotalSeconds;
|
||||
}
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
else if (value is DateTimeOffset dateTimeOffset)
|
||||
{
|
||||
ticks = (long)(dateTimeOffset.ToUniversalTime() - UnixEpoch).TotalSeconds;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException("Expected date object value.");
|
||||
}
|
||||
|
||||
if (ticks < 0)
|
||||
{
|
||||
throw new JsonSerializationException("Cannot convert date value that is before Unix epoch of 00:00:00 UTC on 1 January 1970.");
|
||||
}
|
||||
|
||||
writer.WriteValue(ticks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
bool nullable = ReflectionUtils.IsNullable(objectType);
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
if (!nullable)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
long ticks;
|
||||
|
||||
if (reader.TokenType == JsonToken.Integer)
|
||||
{
|
||||
ticks = (long)reader.Value;
|
||||
}
|
||||
else if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
if (!long.TryParse((string)reader.Value, out ticks))
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert invalid value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token parsing date. Expected Integer or String, got {0}.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
|
||||
}
|
||||
|
||||
if (ticks >= 0)
|
||||
{
|
||||
DateTime d = UnixEpoch.AddSeconds(ticks);
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
Type t = (nullable)
|
||||
? Nullable.GetUnderlyingType(objectType)
|
||||
: objectType;
|
||||
if (t == typeof(DateTimeOffset))
|
||||
{
|
||||
return new DateTimeOffset(d, TimeSpan.Zero);
|
||||
}
|
||||
#endif
|
||||
return d;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Cannot convert value that is before Unix epoch of 00:00:00 UTC on 1 January 1970 to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
RRQMCore/XREF/Newtonsoft.Json/Converters/VersionConverter.cs
Normal file
121
RRQMCore/XREF/Newtonsoft.Json/Converters/VersionConverter.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using RRQMCore.XREF.Newtonsoft.Json.Utilities;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Version"/> to and from a string (e.g. <c>"1.2.3.4"</c>).
|
||||
/// </summary>
|
||||
public class VersionConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
}
|
||||
else if (value is Version)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonSerializationException("Expected Version object value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the JSON representation of the object.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reader.TokenType == JsonToken.String)
|
||||
{
|
||||
try
|
||||
{
|
||||
Version v = new Version((string)reader.Value);
|
||||
return v;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Error parsing version string: {0}".FormatWith(CultureInfo.InvariantCulture, reader.Value), ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw JsonSerializationException.Create(reader, "Unexpected token or value when parsing version. Token: {0}, Value: {1}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType, reader.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can convert the specified object type.
|
||||
/// </summary>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(Version);
|
||||
}
|
||||
}
|
||||
}
|
||||
2253
RRQMCore/XREF/Newtonsoft.Json/Converters/XmlNodeConverter.cs
Normal file
2253
RRQMCore/XREF/Newtonsoft.Json/Converters/XmlNodeConverter.cs
Normal file
File diff suppressed because it is too large
Load Diff
58
RRQMCore/XREF/Newtonsoft.Json/DateFormatHandling.cs
Normal file
58
RRQMCore/XREF/Newtonsoft.Json/DateFormatHandling.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how dates are formatted when writing JSON text.
|
||||
/// </summary>
|
||||
public enum DateFormatHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Dates are written in the ISO 8601 format, e.g. <c>"2012-03-21T05:40Z"</c>.
|
||||
/// </summary>
|
||||
IsoDateFormat,
|
||||
|
||||
/// <summary>
|
||||
/// Dates are written in the Microsoft JSON format, e.g. <c>"\/Date(1198908717056)\/"</c>.
|
||||
/// </summary>
|
||||
MicrosoftDateFormat
|
||||
}
|
||||
}
|
||||
65
RRQMCore/XREF/Newtonsoft.Json/DateParseHandling.cs
Normal file
65
RRQMCore/XREF/Newtonsoft.Json/DateParseHandling.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed when reading JSON text.
|
||||
/// </summary>
|
||||
public enum DateParseHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Date formatted strings are not parsed to a date type and are read as strings.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed to <see cref="DateTime"/>.
|
||||
/// </summary>
|
||||
DateTime = 1,
|
||||
|
||||
#if HAVE_DATE_TIME_OFFSET
|
||||
/// <summary>
|
||||
/// Date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed to <see cref="DateTimeOffset"/>.
|
||||
/// </summary>
|
||||
DateTimeOffset = 2
|
||||
#endif
|
||||
}
|
||||
}
|
||||
71
RRQMCore/XREF/Newtonsoft.Json/DateTimeZoneHandling.cs
Normal file
71
RRQMCore/XREF/Newtonsoft.Json/DateTimeZoneHandling.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how to treat the time value when converting between string and <see cref="DateTime"/>.
|
||||
/// </summary>
|
||||
public enum DateTimeZoneHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Treat as local time. If the <see cref="DateTime"/> object represents a Coordinated Universal Time (UTC), it is converted to the local time.
|
||||
/// </summary>
|
||||
Local = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Treat as a UTC. If the <see cref="DateTime"/> object represents a local time, it is converted to a UTC.
|
||||
/// </summary>
|
||||
Utc = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Treat as a local time if a <see cref="DateTime"/> is being converted to a string.
|
||||
/// If a string is being converted to <see cref="DateTime"/>, convert to a local time if a time zone is specified.
|
||||
/// </summary>
|
||||
Unspecified = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Time zone information should be preserved when converting.
|
||||
/// </summary>
|
||||
RoundtripKind = 3
|
||||
}
|
||||
}
|
||||
82
RRQMCore/XREF/Newtonsoft.Json/DefaultValueHandling.cs
Normal file
82
RRQMCore/XREF/Newtonsoft.Json/DefaultValueHandling.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default value handling options for the <see cref="JsonSerializer"/>.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code lang="cs" source="..\Src\RRQMCore.XREF.Newtonsoft.Json.Tests\Documentation\SerializationTests.cs" region="ReducingSerializedJsonSizeDefaultValueHandlingObject" title="DefaultValueHandling Class" />
|
||||
/// <code lang="cs" source="..\Src\RRQMCore.XREF.Newtonsoft.Json.Tests\Documentation\SerializationTests.cs" region="ReducingSerializedJsonSizeDefaultValueHandlingExample" title="DefaultValueHandling Ignore Example" />
|
||||
/// </example>
|
||||
[Flags]
|
||||
public enum DefaultValueHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Include members where the member value is the same as the member's default value when serializing objects.
|
||||
/// Included members are written to JSON. Has no effect when deserializing.
|
||||
/// </summary>
|
||||
Include = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Ignore members where the member value is the same as the member's default value when serializing objects
|
||||
/// so that it is not written to JSON.
|
||||
/// This option will ignore all default values (e.g. <c>null</c> for objects and nullable types; <c>0</c> for integers,
|
||||
/// decimals and floating point numbers; and <c>false</c> for booleans). The default value ignored can be changed by
|
||||
/// placing the <see cref="DefaultValueAttribute"/> on the property.
|
||||
/// </summary>
|
||||
Ignore = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Members with a default value but no JSON will be set to their default value when deserializing.
|
||||
/// </summary>
|
||||
Populate = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Ignore members where the member value is the same as the member's default value when serializing objects
|
||||
/// and set members to their default value when deserializing.
|
||||
/// </summary>
|
||||
IgnoreAndPopulate = Ignore | Populate
|
||||
}
|
||||
}
|
||||
67
RRQMCore/XREF/Newtonsoft.Json/FloatFormatHandling.cs
Normal file
67
RRQMCore/XREF/Newtonsoft.Json/FloatFormatHandling.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
using System;
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies float format handling options when writing special floating point numbers, e.g. <see cref="Double.NaN"/>,
|
||||
/// <see cref="Double.PositiveInfinity"/> and <see cref="Double.NegativeInfinity"/> with <see cref="JsonWriter"/>.
|
||||
/// </summary>
|
||||
public enum FloatFormatHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Write special floating point values as strings in JSON, e.g. <c>"NaN"</c>, <c>"Infinity"</c>, <c>"-Infinity"</c>.
|
||||
/// </summary>
|
||||
String = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Write special floating point values as symbols in JSON, e.g. <c>NaN</c>, <c>Infinity</c>, <c>-Infinity</c>.
|
||||
/// Note that this will produce non-valid JSON.
|
||||
/// </summary>
|
||||
Symbol = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Write special floating point values as the property's default value in JSON, e.g. 0.0 for a <see cref="Double"/> property, <c>null</c> for a <see cref="Nullable{T}"/> of <see cref="Double"/> property.
|
||||
/// </summary>
|
||||
DefaultValue = 2
|
||||
}
|
||||
}
|
||||
58
RRQMCore/XREF/Newtonsoft.Json/FloatParseHandling.cs
Normal file
58
RRQMCore/XREF/Newtonsoft.Json/FloatParseHandling.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
|
||||
/// </summary>
|
||||
public enum FloatParseHandling
|
||||
{
|
||||
/// <summary>
|
||||
/// Floating point numbers are parsed to <see cref="Double"/>.
|
||||
/// </summary>
|
||||
Double = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Floating point numbers are parsed to <see cref="Decimal"/>.
|
||||
/// </summary>
|
||||
Decimal = 1
|
||||
}
|
||||
}
|
||||
35
RRQMCore/XREF/Newtonsoft.Json/FormatterAssemblyStyle.cs
Normal file
35
RRQMCore/XREF/Newtonsoft.Json/FormatterAssemblyStyle.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
#if HAVE_OBSOLETE_FORMATTER_ASSEMBLY_STYLE
|
||||
|
||||
namespace System.Runtime.Serialization.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the method that will be used during deserialization for locating and loading assemblies.
|
||||
/// </summary>
|
||||
[Obsolete("FormatterAssemblyStyle is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
|
||||
public enum FormatterAssemblyStyle
|
||||
{
|
||||
/// <summary>
|
||||
/// In simple mode, the assembly used during deserialization need not match exactly the assembly used during serialization. Specifically, the version numbers need not match as the <see cref="M:System.Reflection.Assembly.LoadWithPartialName(String)"/> method is used to load the assembly.
|
||||
/// </summary>
|
||||
Simple = 0,
|
||||
|
||||
/// <summary>
|
||||
/// In full mode, the assembly used during deserialization must match exactly the assembly used during serialization. The <see cref="System.Reflection.Assembly.Load"/> is used to load the assembly.
|
||||
/// </summary>
|
||||
Full = 1
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
58
RRQMCore/XREF/Newtonsoft.Json/Formatting.cs
Normal file
58
RRQMCore/XREF/Newtonsoft.Json/Formatting.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#region License
|
||||
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#endregion License
|
||||
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies formatting options for the <see cref="JsonTextWriter"/>.
|
||||
/// </summary>
|
||||
public enum Formatting
|
||||
{
|
||||
/// <summary>
|
||||
/// No special formatting is applied. This is the default.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Causes child objects to be indented according to the <see cref="JsonTextWriter.Indentation"/> and <see cref="JsonTextWriter.IndentChar"/> settings.
|
||||
/// </summary>
|
||||
Indented = 1
|
||||
}
|
||||
}
|
||||
34
RRQMCore/XREF/Newtonsoft.Json/IArrayPool.cs
Normal file
34
RRQMCore/XREF/Newtonsoft.Json/IArrayPool.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// API首页:https://www.yuque.com/eo2w71/rrqm
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
namespace RRQMCore.XREF.Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an interface for using pooled arrays.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The array type content.</typeparam>
|
||||
public interface IArrayPool<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Rent an array from the pool. This array must be returned when it is no longer needed.
|
||||
/// </summary>
|
||||
/// <param name="minimumLength">The minimum required length of the array. The returned array may be longer.</param>
|
||||
/// <returns>The rented array from the pool. This array must be returned when it is no longer needed.</returns>
|
||||
T[] Rent(int minimumLength);
|
||||
|
||||
/// <summary>
|
||||
/// Return an array to the pool.
|
||||
/// </summary>
|
||||
/// <param name="array">The array that is being returned.</param>
|
||||
void Return(T[] array);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user