mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 01:46:44 +08:00
RRQMSocket系8.0预发布版
This commit is contained in:
341
.gitignore
vendored
341
.gitignore
vendored
@@ -1,341 +0,0 @@
|
|||||||
## 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
201
LICENSE
@@ -1,201 +0,0 @@
|
|||||||
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
301
README.md
@@ -1,301 +0,0 @@
|
|||||||
<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)
|
|
||||||
@@ -1,952 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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>
|
|
||||||
[System.Diagnostics.DebuggerDisplay("Len={Len}")]
|
|
||||||
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 => this.Len - this.Pos;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 还能读取的长度,计算为<see cref="Len"/>与<see cref="Pos"/>的差值。
|
|
||||||
/// </summary>
|
|
||||||
public long CanReadLength => 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 => ratio;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value < 1.5)
|
|
||||||
{
|
|
||||||
value = 1.5f;
|
|
||||||
}
|
|
||||||
ratio = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 字节实例
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Buffer => 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 => this.holding;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Int真实长度
|
|
||||||
/// </summary>
|
|
||||||
public int Len => (int)this.length;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 真实长度
|
|
||||||
/// </summary>
|
|
||||||
public override long Length => this.length;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// int型流位置
|
|
||||||
/// </summary>
|
|
||||||
public int Pos
|
|
||||||
{
|
|
||||||
get => (int)this.position;
|
|
||||||
set => this.position = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 流位置
|
|
||||||
/// </summary>
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => this.position;
|
|
||||||
set => this.position = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 使用状态
|
|
||||||
/// </summary>
|
|
||||||
public bool Using => 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>
|
|
||||||
/// 读取数据,然后递增Pos
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buffer"></param>
|
|
||||||
/// <param name="offset"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="ByteBlockDisposedException"></exception>
|
|
||||||
public override int Read(byte[] buffer, int offset, int length)
|
|
||||||
{
|
|
||||||
if (!this.@using)
|
|
||||||
{
|
|
||||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
|
||||||
}
|
|
||||||
int len = this._buffer.Length - this.position > length ? length : this._buffer.Length - (int)this.position;
|
|
||||||
Array.Copy(this._buffer, this.position, buffer, offset, len);
|
|
||||||
this.position += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 读取数据,然后递增Pos
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buffer"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int Read(byte[] buffer)
|
|
||||||
{
|
|
||||||
return this.Read(buffer, 0, buffer.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 读取数据,然后递增Pos
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buffer"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int Read(out byte[] buffer,int length)
|
|
||||||
{
|
|
||||||
buffer = new byte[length];
|
|
||||||
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"/>值。
|
|
||||||
/// <para>读取时必须使用ReadString</para>
|
|
||||||
/// </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
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换为UTF-8字符
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return this.ToString(0, this.Len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换为UTF-8字符
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="offset">偏移量</param>
|
|
||||||
/// <param name="length">长度</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public string ToString(int offset, int length)
|
|
||||||
{
|
|
||||||
if (!this.@using)
|
|
||||||
{
|
|
||||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
|
||||||
}
|
|
||||||
return Encoding.UTF8.GetString(this._buffer, offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换为UTF-8字符
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="offset">偏移量</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public string ToString(int offset)
|
|
||||||
{
|
|
||||||
if (!this.@using)
|
|
||||||
{
|
|
||||||
throw new ByteBlockDisposedException(ResType.ByteBlockDisposed.GetResString());
|
|
||||||
}
|
|
||||||
return Encoding.UTF8.GetString(this._buffer, offset, this.Len - offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,472 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => autoZero;
|
|
||||||
set => autoZero = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 键容量
|
|
||||||
/// </summary>
|
|
||||||
public static int KeyCapacity
|
|
||||||
{
|
|
||||||
get => keyCapacity;
|
|
||||||
set => keyCapacity = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单个块最大值
|
|
||||||
/// </summary>
|
|
||||||
public static int MaxBlockSize => maxBlockSize;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 允许的内存池最大值
|
|
||||||
/// </summary>
|
|
||||||
public static long MaxSize
|
|
||||||
{
|
|
||||||
get => maxSize;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value < 1024)
|
|
||||||
{
|
|
||||||
value = 1024;
|
|
||||||
}
|
|
||||||
maxSize = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 单个块最小值
|
|
||||||
/// </summary>
|
|
||||||
public static int MinBlockSize => 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;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
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 => 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,871 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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一致。
|
|
||||||
/// <para>该集合虽然是线程安全,但是不支持在foreach时修改集合,仅可以遍历成员。</para>
|
|
||||||
/// </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(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.maxCount;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 长度
|
|
||||||
/// </summary>
|
|
||||||
public new int Count => 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.overflowWait;
|
|
||||||
set => this.overflowWait = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Action<bool> onQueueChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 在队列修改时
|
|
||||||
/// </summary>
|
|
||||||
public Action<bool> OnQueueChanged
|
|
||||||
{
|
|
||||||
get => this.onQueueChanged;
|
|
||||||
set => this.onQueueChanged = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool free;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否有空位允许入队
|
|
||||||
/// </summary>
|
|
||||||
public bool Free => 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 => this.maxSize;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value < 1)
|
|
||||||
{
|
|
||||||
value = 1;
|
|
||||||
}
|
|
||||||
this.maxSize = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 实际尺寸
|
|
||||||
/// </summary>
|
|
||||||
public long ActualSize => 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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq;
|
|
||||||
|
|
||||||
namespace RRQMCore
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表示byte的位集合
|
|
||||||
/// 位索引为高位到低位顺序
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerDisplay("{value}")]
|
|
||||||
[DebuggerTypeProxy(typeof(DebugView))]
|
|
||||||
public struct ByteBits : IComparable<ByteBits>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 字节值
|
|
||||||
/// </summary>
|
|
||||||
private byte value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 右移运算
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="count">移动位数</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ByteBits MoveRight(int count)
|
|
||||||
{
|
|
||||||
return (byte)(this.value >> count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 左移运算
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="count">移动位数</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ByteBits MoveLeft(int count)
|
|
||||||
{
|
|
||||||
return (byte)(this.value << count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 取高位
|
|
||||||
/// 相当于右移8-count个单位
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="count">位的数量</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ByteBits Take(int count)
|
|
||||||
{
|
|
||||||
return this.MoveRight(8 - count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从指定索引位置取高位
|
|
||||||
/// 相当于先左移index个单位再右移8-count个单位
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index">索引</param>
|
|
||||||
/// <param name="count">位的数量</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public ByteBits Take(int index, int count)
|
|
||||||
{
|
|
||||||
return this.MoveLeft(index).MoveRight(8 - count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// byte的位集合
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">字节</param>
|
|
||||||
private ByteBits(byte value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取或设置指定位的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="index">由高到低的位索引</param>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool this[int index]
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (index < 0 || index > 7)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException("index", "index为0到7之间");
|
|
||||||
}
|
|
||||||
return ((this.value & (128 >> index)) > 0) ? true : false;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (index < 0 || index > 7)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException("index", "index为0到7之间");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == true)
|
|
||||||
{
|
|
||||||
this.value = (byte)(this.value | (128 >> index));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.value = (byte)(this.value & (byte.MaxValue - (128 >> index)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 字符串显示各个位的值
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
ByteBits bits = this;
|
|
||||||
return string.Join(", ", Enumerable.Range(0, 8).Select(index => bits[index] ? "1" : "0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从byte类型隐式转换
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static implicit operator ByteBits(byte value)
|
|
||||||
{
|
|
||||||
return new ByteBits(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐式转换为byte类型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bits"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static implicit operator byte(ByteBits bits)
|
|
||||||
{
|
|
||||||
return bits.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取哈希码
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return this.value.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 比较是否和目标相等
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj">目标</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (obj is ByteBits) && obj.GetHashCode() == this.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 比较
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="other">目标</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
int IComparable<ByteBits>.CompareTo(ByteBits other)
|
|
||||||
{
|
|
||||||
if (this == other)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.value > other.value)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 调试视图
|
|
||||||
/// </summary>
|
|
||||||
private class DebugView
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 查看的对象
|
|
||||||
/// </summary>
|
|
||||||
private ByteBits bits;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 调试视图
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bits">查看的对象</param>
|
|
||||||
public DebugView(ByteBits bits)
|
|
||||||
{
|
|
||||||
this.bits = bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查看的内容
|
|
||||||
/// </summary>
|
|
||||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
|
||||||
public int[] Values
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var bitArray = new int[8];
|
|
||||||
for (var i = 0; i < bitArray.Length; i++)
|
|
||||||
{
|
|
||||||
bitArray[i] = this.bits[i].GetHashCode();
|
|
||||||
}
|
|
||||||
return bitArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 读取锁
|
|
||||||
/// </summary>
|
|
||||||
public struct ReadLock : IDisposable
|
|
||||||
{
|
|
||||||
private ReaderWriterLockSlim _locks;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="locks"></param>
|
|
||||||
public ReadLock(ReaderWriterLockSlim locks)
|
|
||||||
{
|
|
||||||
this._locks = locks;
|
|
||||||
this._locks.EnterReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 释放
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this._locks.ExitReadLock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 写入锁
|
|
||||||
/// </summary>
|
|
||||||
public struct WriteLock : IDisposable
|
|
||||||
{
|
|
||||||
private ReaderWriterLockSlim _locks;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="locks"></param>
|
|
||||||
public WriteLock(ReaderWriterLockSlim locks)
|
|
||||||
{
|
|
||||||
this._locks = locks;
|
|
||||||
this._locks.EnterWriteLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 释放
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this._locks.ExitWriteLock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,456 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => @default;
|
|
||||||
|
|
||||||
private static EndianType @defaultEndianType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 默认大小端切换。
|
|
||||||
/// </summary>
|
|
||||||
public static EndianType DefaultEndianType
|
|
||||||
{
|
|
||||||
get => @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 => 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 ushort
|
|
||||||
|
|
||||||
#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 ulong
|
|
||||||
|
|
||||||
#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 bool
|
|
||||||
|
|
||||||
#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 char
|
|
||||||
|
|
||||||
#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 short
|
|
||||||
|
|
||||||
#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 int
|
|
||||||
|
|
||||||
#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 long
|
|
||||||
|
|
||||||
#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 uint
|
|
||||||
|
|
||||||
#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 float
|
|
||||||
|
|
||||||
#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 long
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 RRQMCoreUtility
|
|
||||||
{
|
|
||||||
#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 arrayType = typeof(Array);
|
|
||||||
public static readonly Type listType = typeof(IList);
|
|
||||||
public static readonly Type nullableType = typeof(Nullable<>);
|
|
||||||
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RRQMCore.Converter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 转换器接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IConverter<TSource>
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换器执行顺序
|
|
||||||
/// <para>该属性值越小,越靠前执行。值相等时,按添加先后顺序</para>
|
|
||||||
/// <para>该属性效果,仅在<see cref="RRQMConverter{TSource}.Add(IConverter{TSource})"/>之前设置有效。</para>
|
|
||||||
/// </summary>
|
|
||||||
int Order { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试将源数据转换目标类型对象
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="targetType"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool TryConvertFrom(TSource source,Type targetType,out object target);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试将目标类型对象转换源数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool TryConvertTo(object target,out TSource source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace RRQMCore.Converter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 转换器
|
|
||||||
/// </summary>
|
|
||||||
public class RRQMConverter<TSource>
|
|
||||||
{
|
|
||||||
private readonly List<IConverter<TSource>> converters = new List<IConverter<TSource>>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="converter">插件</param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
public void Add(IConverter<TSource> converter)
|
|
||||||
{
|
|
||||||
if (converter == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
}
|
|
||||||
foreach (var item in this.converters)
|
|
||||||
{
|
|
||||||
if (item.GetType()==converter.GetType())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.converters.Add(converter);
|
|
||||||
|
|
||||||
this.converters.Sort(delegate (IConverter<TSource> x, IConverter<TSource> y)
|
|
||||||
{
|
|
||||||
if (x.Order == y.Order) return 0;
|
|
||||||
else if (x.Order > y.Order) return 1;
|
|
||||||
else return -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清除所有插件
|
|
||||||
/// </summary>
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
this.converters.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将源数据转换目标类型对象
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="targetType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object ConvertFrom(TSource source, Type targetType)
|
|
||||||
{
|
|
||||||
object result;
|
|
||||||
foreach (var item in this.converters)
|
|
||||||
{
|
|
||||||
if (item.TryConvertFrom(source, targetType, out result))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RRQMException($"{source}无法转换为{targetType}类型。");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将目标类型对象转换源数据
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public TSource ConvertTo(object target)
|
|
||||||
{
|
|
||||||
foreach (var item in this.converters)
|
|
||||||
{
|
|
||||||
if (item.TryConvertTo(target,out TSource source))
|
|
||||||
{
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RRQMException($"{target}无法转换为{typeof(TSource)}类型。");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="converter"></param>
|
|
||||||
public void Remove(IConverter<TSource> converter)
|
|
||||||
{
|
|
||||||
if (converter == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
}
|
|
||||||
this.converters.Remove(converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
public void Remove(Type type)
|
|
||||||
{
|
|
||||||
for (int i = this.converters.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
IConverter<TSource> plugin = this.converters[i];
|
|
||||||
if (plugin.GetType() == type)
|
|
||||||
{
|
|
||||||
this.converters.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
using RRQMCore.XREF.Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace RRQMCore.Converter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// String类型数据转换器
|
|
||||||
/// </summary>
|
|
||||||
public class StringConverter : RRQMConverter<string>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
public StringConverter()
|
|
||||||
{
|
|
||||||
this.Add(new StringToPrimitiveConverter());
|
|
||||||
this.Add(new JsonStringToClassConverter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// String值转换为基础类型。
|
|
||||||
/// </summary>
|
|
||||||
public class StringToPrimitiveConverter : IConverter<string>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
public int Order { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="targetType"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryConvertFrom(string source, Type targetType, out object target)
|
|
||||||
{
|
|
||||||
if (targetType.IsPrimitive || targetType == RRQMCoreUtility.stringType)
|
|
||||||
{
|
|
||||||
return RRQMCoreExtensions.TryParseToType(source, targetType, out target);
|
|
||||||
}
|
|
||||||
target = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryConvertTo(object target, out string source)
|
|
||||||
{
|
|
||||||
if (target != null)
|
|
||||||
{
|
|
||||||
Type type = target.GetType();
|
|
||||||
if (type.IsPrimitive || type == RRQMCoreUtility.stringType)
|
|
||||||
{
|
|
||||||
source = target.ToString();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
source = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Json字符串转到对应类
|
|
||||||
/// </summary>
|
|
||||||
public class JsonStringToClassConverter : IConverter<string>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
public int Order { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="targetType"></param>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryConvertFrom(string source, Type targetType, out object target)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
target = JsonConvert.DeserializeObject(source, targetType);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
target = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="target"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryConvertTo(object target, out string source)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
source = target.ToJsonString();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
source = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,721 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace RRQMCore.Dependency
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 注入容器接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IContainer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 注册临时映射
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
public void RegisterTransient<TInterface, TImplementation>() where TImplementation : TInterface;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册单例
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
/// <param name="singleton"></param>
|
|
||||||
public void RegisterSingleton<TInterface, TImplementation>(TImplementation singleton) where TImplementation : TInterface;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册单例
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
public void RegisterSingleton<TInterface, TImplementation>() where TImplementation : TInterface;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建类型对应的实例
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T Resolve<T>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建类型对应的实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object Resolve(Type type);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// IOC容器
|
|
||||||
/// </summary>
|
|
||||||
public class Container : IContainer
|
|
||||||
{
|
|
||||||
private readonly Hashtable registrations;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
public Container()
|
|
||||||
{
|
|
||||||
this.registrations = new Hashtable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
public void RegisterTransient<TInterface, TImplementation>() where TImplementation : TInterface
|
|
||||||
{
|
|
||||||
if (this.registrations.ContainsKey(typeof(TInterface)))
|
|
||||||
{
|
|
||||||
this.registrations[typeof(TInterface)] = typeof(TImplementation);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.registrations.Add(typeof(TInterface), typeof(TImplementation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
/// <param name="singleton"></param>
|
|
||||||
public void RegisterSingleton<TInterface, TImplementation>(TImplementation singleton) where TImplementation : TInterface
|
|
||||||
{
|
|
||||||
if (this.registrations.ContainsKey(typeof(TInterface)))
|
|
||||||
{
|
|
||||||
this.registrations[typeof(TInterface)] = singleton;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.registrations.Add(typeof(TInterface), singleton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TInterface"></typeparam>
|
|
||||||
/// <typeparam name="TImplementation"></typeparam>
|
|
||||||
public void RegisterSingleton<TInterface, TImplementation>() where TImplementation : TInterface
|
|
||||||
{
|
|
||||||
if (this.registrations.ContainsKey(typeof(TInterface)))
|
|
||||||
{
|
|
||||||
this.registrations[typeof(TInterface)] = this.Resolve<TImplementation>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.registrations.Add(typeof(TInterface), this.Resolve<TImplementation>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="interfaceType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private object Create(Type interfaceType)
|
|
||||||
{
|
|
||||||
object value = this.registrations[interfaceType];
|
|
||||||
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
if (interfaceType.IsPrimitive || interfaceType == typeof(string))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var constructors = interfaceType.GetConstructors();
|
|
||||||
if (constructors.Length > 0)
|
|
||||||
{
|
|
||||||
var parameters = constructors[0].GetParameters();
|
|
||||||
object[] ps = new object[parameters.Length];
|
|
||||||
for (int i = 0; i < parameters.Length; i++)
|
|
||||||
{
|
|
||||||
if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
|
|
||||||
{
|
|
||||||
if (parameters[i].HasDefaultValue)
|
|
||||||
{
|
|
||||||
ps[i] = parameters[i].DefaultValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps[i] = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps[i] = this.Create(parameters[i].ParameterType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Activator.CreateInstance(interfaceType, ps);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new RRQMException($"没有找到类型{interfaceType.Name}的公共构造函数。");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (value is Type type)
|
|
||||||
{
|
|
||||||
var constructors = type.GetConstructors();
|
|
||||||
if (constructors.Length > 0)
|
|
||||||
{
|
|
||||||
var parameters = constructors[0].GetParameters();
|
|
||||||
object[] ps = new object[parameters.Length];
|
|
||||||
for (int i = 0; i < parameters.Length; i++)
|
|
||||||
{
|
|
||||||
if (parameters[i].ParameterType.IsPrimitive || parameters[i].ParameterType == typeof(string))
|
|
||||||
{
|
|
||||||
if (parameters[i].HasDefaultValue)
|
|
||||||
{
|
|
||||||
ps[i] = parameters[i].DefaultValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps[i] = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ps[i] = this.Create(parameters[i].ParameterType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Activator.CreateInstance(type, ps);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new RRQMException($"没有找到类型{interfaceType.Name}的公共构造函数。");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T Resolve<T>()
|
|
||||||
{
|
|
||||||
return (T)this.Create(typeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object Resolve(Type type)
|
|
||||||
{
|
|
||||||
return this.Create(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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>
|
|
||||||
public class DependencyProperty
|
|
||||||
{
|
|
||||||
private DependencyProperty()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private string name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性名
|
|
||||||
/// </summary>
|
|
||||||
public string Name => this.name;
|
|
||||||
|
|
||||||
private Type owner;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 所属类型
|
|
||||||
/// </summary>
|
|
||||||
public Type Owner => this.owner;
|
|
||||||
|
|
||||||
private Type valueType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 值类型
|
|
||||||
/// </summary>
|
|
||||||
public Type ValueType => this.valueType;
|
|
||||||
|
|
||||||
private object value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 默认值
|
|
||||||
/// </summary>
|
|
||||||
public object DefauleValue => 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)
|
|
||||||
{
|
|
||||||
DependencyProperty dp = new DependencyProperty();
|
|
||||||
dp.name = propertyName;
|
|
||||||
dp.valueType = valueType;
|
|
||||||
dp.owner = owner;
|
|
||||||
dp.SetDefauleValue(value);
|
|
||||||
return dp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 interface IRRQMDependencyObject : System.IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取依赖注入的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dependencyProperty"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
object GetValue(DependencyProperty dependencyProperty);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取依赖注入的值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="dependencyProperty"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T GetValue<T>(DependencyProperty dependencyProperty);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置依赖注入的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dependencyProperty"></param>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
public RRQMDependencyObject SetValue(DependencyProperty dependencyProperty, object value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 依赖项对象
|
|
||||||
/// </summary>
|
|
||||||
public class RRQMDependencyObject : IRRQMDependencyObject, System.IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
public RRQMDependencyObject()
|
|
||||||
{
|
|
||||||
this.dp = new ConcurrentDictionary<DependencyProperty, object>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
|
|
||||||
private ConcurrentDictionary<DependencyProperty, object> dp;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断是否已释放。
|
|
||||||
/// </summary>
|
|
||||||
protected volatile bool disposedValue;
|
|
||||||
|
|
||||||
/// <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)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (T)this.GetValue(dependencyProperty);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 释放
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing"></param>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!this.disposedValue)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
// TODO: 释放托管状态(托管对象)
|
|
||||||
}
|
|
||||||
this.dp.Clear();
|
|
||||||
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
|
|
||||||
// TODO: 将大型字段设置为 null
|
|
||||||
this.disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
|
|
||||||
// ~RRQMDependencyObject()
|
|
||||||
// {
|
|
||||||
// // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
|
|
||||||
// Dispose(disposing: false);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 释放资源
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
|
|
||||||
this.Dispose(disposing: true);
|
|
||||||
System.GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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>
|
|
||||||
[Flags]
|
|
||||||
public enum Operation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 无任何状态
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 已处理
|
|
||||||
/// </summary>
|
|
||||||
Handled = 1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 允许该操作
|
|
||||||
/// </summary>
|
|
||||||
Permit = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 是否允许操作
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPermitOperation
|
|
||||||
{
|
|
||||||
get => this.operation.HasFlag(Operation.Permit);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
this.AddOperation(Operation.Permit);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.RemoveOperation(Operation.Permit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否已处理
|
|
||||||
/// </summary>
|
|
||||||
public bool Handled
|
|
||||||
{
|
|
||||||
get => this.operation.HasFlag(Operation.Handled);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
this.AddOperation(Operation.Handled);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.RemoveOperation(Operation.Handled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Operation operation;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 操作类型。
|
|
||||||
/// </summary>
|
|
||||||
public Operation Operation => this.operation;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operation"></param>
|
|
||||||
public void AddOperation(Operation operation)
|
|
||||||
{
|
|
||||||
this.operation |= operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 移除操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="operation"></param>
|
|
||||||
public void RemoveOperation(Operation operation)
|
|
||||||
{
|
|
||||||
this.operation ^= operation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
namespace RRQMCore.Exceptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 异常助手
|
|
||||||
/// </summary>
|
|
||||||
public class ThrowHelper
|
|
||||||
{
|
|
||||||
static ThrowHelper()
|
|
||||||
{
|
|
||||||
throwHelper = new ThrowHelper();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ThrowHelper throwHelper;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 默认实例
|
|
||||||
/// </summary>
|
|
||||||
public static ThrowHelper Default => throwHelper;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,735 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Log;
|
|
||||||
using RRQMCore.XREF.Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace RRQMCore.Extensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 辅助扩展类
|
|
||||||
/// </summary>
|
|
||||||
public static class RRQMCoreExtensions
|
|
||||||
{
|
|
||||||
#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 日志
|
|
||||||
|
|
||||||
#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, Formatting.None));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 转换为json字符串。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ToJsonString(this object obj)
|
|
||||||
{
|
|
||||||
return JsonConvert.SerializeObject(obj, Formatting.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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转换
|
|
||||||
|
|
||||||
#region 字符串扩展
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断字符串compare 在 input字符串中出现的次数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">源字符串</param>
|
|
||||||
/// <param name="compare">用于比较的字符串</param>
|
|
||||||
/// <returns>字符串compare 在 input字符串中出现的次数</returns>
|
|
||||||
public static int HitStringCount(this string input, string compare)
|
|
||||||
{
|
|
||||||
int index = input.IndexOf(compare);
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
return 1 + HitStringCount(input.Substring(index + compare.Length), compare);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将字符转换为对应类型。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="destinationType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object ParseToType(this string value, Type destinationType)
|
|
||||||
{
|
|
||||||
object returnValue;
|
|
||||||
if ((value == null) || destinationType.IsInstanceOfType(value))
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
string str = value as string;
|
|
||||||
if ((str != null) && (str.Length == 0))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
|
|
||||||
bool flag = converter.CanConvertFrom(value.GetType());
|
|
||||||
if (!flag)
|
|
||||||
{
|
|
||||||
converter = TypeDescriptor.GetConverter(value.GetType());
|
|
||||||
}
|
|
||||||
if (!flag && !converter.CanConvertTo(destinationType))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("无法转换成类型:" + value.ToString() + "==>" + destinationType);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(" 类型转换出错:" + value.ToString() + "==>" + destinationType, e);
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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="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数据,效果等于<see cref="Encoding.UTF8"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static byte[] ToUTF8Bytes(this string value)
|
|
||||||
{
|
|
||||||
return Encoding.UTF8.GetBytes(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将16进制的字符转换为数组。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hexString"></param>
|
|
||||||
/// <param name="splite"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static byte[] ByHexStringToBytes(this string hexString, string splite = default)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(splite))
|
|
||||||
{
|
|
||||||
hexString = hexString.Replace(splite, string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((hexString.Length % 2) != 0)
|
|
||||||
{
|
|
||||||
hexString += " ";
|
|
||||||
}
|
|
||||||
byte[] returnBytes = new byte[hexString.Length / 2];
|
|
||||||
for (int i = 0; i < returnBytes.Length; i++)
|
|
||||||
{
|
|
||||||
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
|
|
||||||
}
|
|
||||||
return returnBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将16进制的字符转换为int32。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hexString"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static int ByHexStringToInt32(this string hexString)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(hexString))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
return int.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 字节数组扩展
|
|
||||||
/// <summary>
|
|
||||||
/// 转Base64。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ToBase64(this byte[] data)
|
|
||||||
{
|
|
||||||
return Convert.ToBase64String(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 字节数组转16进制字符
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buffer"></param>
|
|
||||||
/// <param name="offset"></param>
|
|
||||||
/// <param name="length"></param>
|
|
||||||
/// <param name="splite"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ByBytesToHexString(this byte[] buffer, int offset, int length, string splite = default)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(splite))
|
|
||||||
{
|
|
||||||
return BitConverter.ToString(buffer, offset, length).Replace("-", string.Empty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return BitConverter.ToString(buffer, offset, length).Replace("-", splite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
/// 获取字节中的指定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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Type扩展
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断该类型是否为可空类型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="theType"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool IsNullableType(this Type theType)
|
|
||||||
{
|
|
||||||
return (theType.IsGenericType && theType.
|
|
||||||
GetGenericTypeDefinition().Equals
|
|
||||||
(RRQMCoreUtility.nullableType));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 类型转换
|
|
||||||
///<summary>
|
|
||||||
/// 将字符串格式化成指定的数据类型
|
|
||||||
///</summary>
|
|
||||||
///<param name="str"></param>
|
|
||||||
///<param name="type"></param>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="splits"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool TryParseToType(string str, Type type, out object value, char[] splits = default)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(str))
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
value = str;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (type.IsArray)
|
|
||||||
{
|
|
||||||
Type elementType = type.GetElementType();
|
|
||||||
string[] strs;
|
|
||||||
if (splits == null)
|
|
||||||
{
|
|
||||||
strs = str.Split(new char[] { ' ', ';', '-', '/' });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strs = str.Split(splits);
|
|
||||||
}
|
|
||||||
|
|
||||||
Array array = Array.CreateInstance(elementType, strs.Length);
|
|
||||||
for (int i = 0, c = strs.Length; i < c; ++i)
|
|
||||||
{
|
|
||||||
object o;
|
|
||||||
if (ConvertSimpleType(strs[i], elementType, out o))
|
|
||||||
{
|
|
||||||
array.SetValue(o, i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = array;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return ConvertSimpleType(str, type, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static bool ConvertSimpleType(string value, Type destinationType, out object returnValue)
|
|
||||||
{
|
|
||||||
if ((value == null) || destinationType.IsInstanceOfType(value))
|
|
||||||
{
|
|
||||||
returnValue = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
{
|
|
||||||
returnValue = default;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
|
|
||||||
bool flag = converter.CanConvertFrom(value.GetType());
|
|
||||||
if (!flag)
|
|
||||||
{
|
|
||||||
converter = TypeDescriptor.GetConverter(value.GetType());
|
|
||||||
}
|
|
||||||
if (!flag && !converter.CanConvertTo(destinationType))
|
|
||||||
{
|
|
||||||
returnValue = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
returnValue = flag ? converter.ConvertFrom(null, null, value) : converter.ConvertTo(null, null, value, destinationType);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
returnValue = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => 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 => this.action;
|
|
||||||
|
|
||||||
private string fullOrder;
|
|
||||||
|
|
||||||
public string FullOrder => 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 => this.description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace RRQMCore.IO
|
|
||||||
{
|
|
||||||
internal class RRQMStreamPool
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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)
|
|
||||||
{
|
|
||||||
lock (typeof(ConsoleLogger))
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 (typeof(FileLogger))
|
|
||||||
{
|
|
||||||
string path = Path.Combine(this.rootPath, DateTime.Now.ToString("[yyyy-MM-dd]") + ".log");
|
|
||||||
File.AppendAllText(path, logString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.autoCreate;
|
|
||||||
set => this.autoCreate = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对象池容量
|
|
||||||
/// </summary>
|
|
||||||
public int Capacity { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 可使用(创建)数量
|
|
||||||
/// </summary>
|
|
||||||
public int FreeSize => 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 244 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB |
@@ -1,93 +0,0 @@
|
|||||||
<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>8.0.0-beta</Version>
|
|
||||||
<LangVersion>9.0</LangVersion>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<Description>此程序集是RRQM的核心开源库,其中包含了内存池、高性能序列化、日志接口在内的很多基本内容。
|
|
||||||
|
|
||||||
更新内容:
|
|
||||||
优化:RRQMBinary支持可空类型序列化。
|
|
||||||
增加:Method,更加方便构建反射。
|
|
||||||
增加:Container,全局注入容器。
|
|
||||||
增加:ReadLock,WriteLock,很方便的和ReaderWriterLockSlim结合。
|
|
||||||
修改:RRQMEventAgrs,支持全局的Handled,Permit命令。
|
|
||||||
|
|
||||||
特别说明:本程序集在源码里内嵌了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>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq.Expressions;
|
|
||||||
|
|
||||||
namespace RRQMCore.Reflection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表达式复制
|
|
||||||
/// </summary>
|
|
||||||
public class ExpressionMapper
|
|
||||||
{
|
|
||||||
private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 字典缓存表达式树
|
|
||||||
/// </summary>
|
|
||||||
public static TOut Trans<TIn, TOut>(TIn tIn)
|
|
||||||
{
|
|
||||||
string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
|
|
||||||
if (!_Dic.ContainsKey(key))
|
|
||||||
{
|
|
||||||
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
|
|
||||||
List<MemberBinding> memberBindingList = new List<MemberBinding>();
|
|
||||||
foreach (var item in typeof(TOut).GetProperties())
|
|
||||||
{
|
|
||||||
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
|
|
||||||
MemberBinding memberBinding = Expression.Bind(item, property);
|
|
||||||
memberBindingList.Add(memberBinding);
|
|
||||||
}
|
|
||||||
foreach (var item in typeof(TOut).GetFields())
|
|
||||||
{
|
|
||||||
MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
|
|
||||||
MemberBinding memberBinding = Expression.Bind(item, property);
|
|
||||||
memberBindingList.Add(memberBinding);
|
|
||||||
}
|
|
||||||
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
|
|
||||||
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, parameterExpression);
|
|
||||||
Func<TIn, TOut> func = lambda.Compile();//拼装是一次性的
|
|
||||||
_Dic[key] = func;
|
|
||||||
}
|
|
||||||
return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RRQMCore.Reflection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表示方法
|
|
||||||
/// </summary>
|
|
||||||
public class Method
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 返回值类型。
|
|
||||||
/// <para>当方法为void或task时,为null</para>
|
|
||||||
/// <para>当方法为task泛型时,为泛型元素类型</para>
|
|
||||||
/// </summary>
|
|
||||||
public Type ReturnType { get; private set; }
|
|
||||||
|
|
||||||
private bool task;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否具有返回值
|
|
||||||
/// </summary>
|
|
||||||
public bool HasReturn { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 方法执行委托
|
|
||||||
/// </summary>
|
|
||||||
private readonly Func<object, object[], object> invoker;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取方法名
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; protected set; }
|
|
||||||
|
|
||||||
|
|
||||||
private MethodInfo info;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 方法信息
|
|
||||||
/// </summary>
|
|
||||||
public MethodInfo Info => this.info;
|
|
||||||
|
|
||||||
private bool isByRef;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否有引用类型
|
|
||||||
/// </summary>
|
|
||||||
public bool IsByRef => this.isByRef;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 方法
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="method">方法信息</param>
|
|
||||||
public Method(MethodInfo method)
|
|
||||||
{
|
|
||||||
this.Name = method.Name;
|
|
||||||
this.info = method;
|
|
||||||
|
|
||||||
foreach (var item in method.GetParameters())
|
|
||||||
{
|
|
||||||
if (item.ParameterType.IsByRef)
|
|
||||||
{
|
|
||||||
this.isByRef = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.invoker = CreateInvoker(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 执行方法。
|
|
||||||
/// <para>当方法为void或task时,会返回null</para>
|
|
||||||
/// <para>当方法为task泛型时,会wait后的值</para>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">实例</param>
|
|
||||||
/// <param name="parameters">参数</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object Invoke(object instance, params object[] parameters)
|
|
||||||
{
|
|
||||||
object re;
|
|
||||||
if (this.isByRef)
|
|
||||||
{
|
|
||||||
re = this.info.Invoke(instance, parameters);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
re = this.invoker.Invoke(instance, parameters);
|
|
||||||
}
|
|
||||||
if (this.task)
|
|
||||||
{
|
|
||||||
Task task = (Task)re;
|
|
||||||
task.Wait();
|
|
||||||
return task.GetType().GetProperty("Result").GetValue(task);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成方法的调用委托
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="method">方法成员信息</param>
|
|
||||||
/// <exception cref="ArgumentException"></exception>
|
|
||||||
/// <returns></returns>
|
|
||||||
private Func<object, object[], object> CreateInvoker(MethodInfo method)
|
|
||||||
{
|
|
||||||
var instance = Expression.Parameter(typeof(object), "instance");
|
|
||||||
var parameters = Expression.Parameter(typeof(object[]), "parameters");
|
|
||||||
|
|
||||||
var instanceCast = method.IsStatic ? null : Expression.Convert(instance, method.DeclaringType);
|
|
||||||
var parametersCast = method.GetParameters().Select((p, i) =>
|
|
||||||
{
|
|
||||||
var parameter = Expression.ArrayIndex(parameters, Expression.Constant(i));
|
|
||||||
return Expression.Convert(parameter, p.ParameterType);
|
|
||||||
});
|
|
||||||
|
|
||||||
var body = Expression.Call(instanceCast, method, parametersCast);
|
|
||||||
|
|
||||||
if (method.ReturnType == typeof(void) || method.ReturnType == typeof(Task))
|
|
||||||
{
|
|
||||||
var action = Expression.Lambda<Action<object, object[]>>(body, instance, parameters).Compile();
|
|
||||||
return (_instance, _parameters) =>
|
|
||||||
{
|
|
||||||
action.Invoke(_instance, _parameters);
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.HasReturn = true;
|
|
||||||
if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
|
|
||||||
{
|
|
||||||
this.task = true;
|
|
||||||
this.ReturnType = method.ReturnType.GetGenericArguments()[0];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.ReturnType = method.ReturnType;
|
|
||||||
}
|
|
||||||
var bodyCast = Expression.Convert(body, typeof(object));
|
|
||||||
return Expression.Lambda<Func<object, object[], object>>(bodyCast, instance, parameters).Compile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace RRQMCore.Reflection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表示属性
|
|
||||||
/// </summary>
|
|
||||||
public class Property
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取器
|
|
||||||
/// </summary>
|
|
||||||
private readonly PropertyGetter geter;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置器
|
|
||||||
/// </summary>
|
|
||||||
private readonly PropertySetter seter;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取属性名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取属性信息
|
|
||||||
/// </summary>
|
|
||||||
public PropertyInfo Info { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">属性信息</param>
|
|
||||||
public Property(PropertyInfo property)
|
|
||||||
{
|
|
||||||
this.Name = property.Name;
|
|
||||||
this.Info = property;
|
|
||||||
|
|
||||||
if (property.CanRead == true)
|
|
||||||
{
|
|
||||||
this.geter = new PropertyGetter(property);
|
|
||||||
}
|
|
||||||
if (property.CanWrite == true)
|
|
||||||
{
|
|
||||||
this.seter = new PropertySetter(property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取属性的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">实例</param>
|
|
||||||
/// <exception cref="NotSupportedException"></exception>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object GetValue(object instance)
|
|
||||||
{
|
|
||||||
if (this.geter == null)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
return this.geter.Invoke(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置属性的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">实例</param>
|
|
||||||
/// <param name="value">值</param>
|
|
||||||
/// <exception cref="NotSupportedException"></exception>
|
|
||||||
public void SetValue(object instance, object value)
|
|
||||||
{
|
|
||||||
if (this.seter == null)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException($"{this.Name}不允许赋值");
|
|
||||||
}
|
|
||||||
this.seter.Invoke(instance, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 类型属性的Setter缓存
|
|
||||||
/// </summary>
|
|
||||||
private static readonly ConcurrentDictionary<Type, Property[]> cached = new ConcurrentDictionary<Type, Property[]>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从类型的属性获取属性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">类型</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Property[] GetProperties(Type type)
|
|
||||||
{
|
|
||||||
return cached.GetOrAdd(type, t => t.GetProperties().Select(p => new Property(p)).ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace RRQMCore.Reflection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表示属性的Getter
|
|
||||||
/// </summary>
|
|
||||||
public class PropertyGetter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// get方法委托
|
|
||||||
/// </summary>
|
|
||||||
private readonly Func<object, object> getFunc;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 表示属性的Getter
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">属性</param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
public PropertyGetter(PropertyInfo property)
|
|
||||||
: this(property?.DeclaringType, property?.Name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 表示类型字段或属性的Getter
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="declaringType">声名属性的类型</param>
|
|
||||||
/// <param name="propertyName">属性的名称</param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
public PropertyGetter(Type declaringType, string propertyName)
|
|
||||||
{
|
|
||||||
if (declaringType == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(declaringType));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyName == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(propertyName));
|
|
||||||
}
|
|
||||||
this.getFunc = CreateGetterDelegate(declaringType, propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取属性的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">实例</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public object Invoke(object instance)
|
|
||||||
{
|
|
||||||
return this.getFunc.Invoke(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建declaringType类型获取property值的委托
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="declaringType">实例的类型</param>
|
|
||||||
/// <param name="propertyName">属性的名称</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static Func<object, object> CreateGetterDelegate(Type declaringType, string propertyName)
|
|
||||||
{
|
|
||||||
var param_instance = Expression.Parameter(typeof(object));
|
|
||||||
var body_instance = Expression.Convert(param_instance, declaringType);
|
|
||||||
var body_property = Expression.Property(body_instance, propertyName);
|
|
||||||
var body_return = Expression.Convert(body_property, typeof(object));
|
|
||||||
|
|
||||||
return Expression.Lambda<Func<object, object>>(body_return, param_instance).Compile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace RRQMCore.Reflection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 表示属性的设置器
|
|
||||||
/// </summary>
|
|
||||||
public class PropertySetter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// set方法委托
|
|
||||||
/// </summary>
|
|
||||||
private readonly Action<object, object> setFunc;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 表示属性的Getter
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">属性</param>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
public PropertySetter(PropertyInfo property)
|
|
||||||
{
|
|
||||||
if (property == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(property));
|
|
||||||
}
|
|
||||||
this.setFunc = CreateSetterDelegate(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置属性的值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="instance">实例</param>
|
|
||||||
/// <param name="value">值</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public void Invoke(object instance, object value)
|
|
||||||
{
|
|
||||||
this.setFunc.Invoke(instance, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建属性的Set委托
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="property">属性</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static Action<object, object> CreateSetterDelegate(PropertyInfo property)
|
|
||||||
{
|
|
||||||
var param_instance = Expression.Parameter(typeof(object));
|
|
||||||
var param_value = Expression.Parameter(typeof(object));
|
|
||||||
|
|
||||||
var body_instance = Expression.Convert(param_instance, property.DeclaringType);
|
|
||||||
var body_value = Expression.Convert(param_value, property.PropertyType);
|
|
||||||
var body_call = Expression.Call(body_instance, property.GetSetMethod(), body_value);
|
|
||||||
|
|
||||||
return Expression.Lambda<Action<object, object>>(body_call, param_instance, param_value).Compile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
324
RRQMCore/Resource.Designer.cs
generated
324
RRQMCore/Resource.Designer.cs
generated
@@ -1,324 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// <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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RRQMCore.Run
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 易用组件
|
|
||||||
/// </summary>
|
|
||||||
public class EasyAction
|
|
||||||
{
|
|
||||||
static ConcurrentDictionary<object, Timer> timers = new ConcurrentDictionary<object, Timer>();
|
|
||||||
/// <summary>
|
|
||||||
/// 延迟执行
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="delayTimeSpan"></param>
|
|
||||||
public static void DelayRun(TimeSpan delayTimeSpan, Action action)
|
|
||||||
{
|
|
||||||
DelayRun(delayTimeSpan.Milliseconds, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 延迟执行
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action"></param>
|
|
||||||
/// <param name="delay"></param>
|
|
||||||
public static void DelayRun(int delay, Action action)
|
|
||||||
{
|
|
||||||
object obj = new object();
|
|
||||||
Timer timer = new Timer((o) =>
|
|
||||||
{
|
|
||||||
if (timers.TryRemove(o, out Timer timer1))
|
|
||||||
{
|
|
||||||
timer1.Dispose();
|
|
||||||
}
|
|
||||||
action?.Invoke();
|
|
||||||
}, obj, delay, Timeout.Infinite);
|
|
||||||
timers.TryAdd(obj, timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.executedCount;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 执行间隔
|
|
||||||
/// </summary>
|
|
||||||
public TimeSpan Interval => this.interval;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 循环次数
|
|
||||||
/// </summary>
|
|
||||||
public int LoopCount => this.loopCount;
|
|
||||||
|
|
||||||
private Action<LoopAction> action;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 执行委托
|
|
||||||
/// </summary>
|
|
||||||
public Action<LoopAction> ExecuteAction => this.action;
|
|
||||||
|
|
||||||
private RunStatus runStatus;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否在运行
|
|
||||||
/// </summary>
|
|
||||||
public RunStatus RunStatus => 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,370 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.status;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 等待数据结果
|
|
||||||
/// </summary>
|
|
||||||
public T WaitResult => 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。
|
|
||||||
/// 设置<see cref="WaitResult"/>为null。然后重置状态为<see cref="WaitDataStatus.Default"/>,waitHandle.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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 => this.message;
|
|
||||||
set => this.message = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 标记号
|
|
||||||
/// </summary>
|
|
||||||
public int Sign
|
|
||||||
{
|
|
||||||
get => this.sign;
|
|
||||||
set => this.sign = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 状态
|
|
||||||
/// </summary>
|
|
||||||
public byte Status
|
|
||||||
{
|
|
||||||
get => this.status;
|
|
||||||
set => this.status = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,567 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Extensions;
|
|
||||||
using RRQMCore.Reflection;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
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 == RRQMCoreUtility.byteType)
|
|
||||||
{
|
|
||||||
data = new byte[] { (byte)graph };
|
|
||||||
}
|
|
||||||
else if (enumValType == RRQMCoreUtility.shortType)
|
|
||||||
{
|
|
||||||
data = RRQMBitConverter.Default.GetBytes((short)graph);
|
|
||||||
}
|
|
||||||
else if (enumValType == RRQMCoreUtility.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)
|
|
||||||
{
|
|
||||||
bool nullable = type.IsNullableType();
|
|
||||||
if (nullable)
|
|
||||||
{
|
|
||||||
type = type.GenericTypeArguments[0];
|
|
||||||
}
|
|
||||||
dynamic obj;
|
|
||||||
int len = RRQMBitConverter.Default.ToInt32(datas, offset);
|
|
||||||
offset += 4;
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
if (type == RRQMCoreUtility.stringType)
|
|
||||||
{
|
|
||||||
obj = Encoding.UTF8.GetString(datas, offset, len);
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.byteType)
|
|
||||||
{
|
|
||||||
obj = datas[offset];
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.sbyteType)
|
|
||||||
{
|
|
||||||
obj = (sbyte)(RRQMBitConverter.Default.ToInt16(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.boolType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToBoolean(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.shortType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToInt16(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.ushortType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToUInt16(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.intType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToInt32(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.uintType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToUInt32(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.longType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToInt64(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.ulongType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToUInt64(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.floatType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToSingle(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.doubleType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToDouble(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.decimalType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToDouble(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.charType)
|
|
||||||
{
|
|
||||||
obj = (RRQMBitConverter.Default.ToChar(datas, offset));
|
|
||||||
}
|
|
||||||
else if (type == RRQMCoreUtility.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 == RRQMCoreUtility.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
|
|
||||||
{
|
|
||||||
if (nullable)
|
|
||||||
{
|
|
||||||
obj = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
obj = type.GetDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset += len;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private dynamic DeserializeClass(Type type, byte[] datas, int offset, int length)
|
|
||||||
{
|
|
||||||
SerializObject 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;
|
|
||||||
|
|
||||||
if (instanceObject.Properties.ContainsKey(propertyName))
|
|
||||||
{
|
|
||||||
PropertyInfo property = instanceObject.Properties[propertyName];
|
|
||||||
object obj = this.Deserialize(property.PropertyType, datas, ref offset);
|
|
||||||
property.SetValue(instance, obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int pLen = RRQMBitConverter.Default.ToInt32(datas, offset);
|
|
||||||
offset += 4;
|
|
||||||
offset += pLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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.Public);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, SerializObject> InstanceCache = new ConcurrentDictionary<string, SerializObject>();
|
|
||||||
|
|
||||||
private static SerializObject GetOrAddInstance(Type type)
|
|
||||||
{
|
|
||||||
if (InstanceCache.TryGetValue(type.FullName, out SerializObject instance))
|
|
||||||
{
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
if (type.IsArray)//数组
|
|
||||||
{
|
|
||||||
SerializObject typeInfo = InstanceCache.GetOrAdd(type.FullName, (Func<string, SerializObject>)((v) =>
|
|
||||||
{
|
|
||||||
SerializObject instanceObject = new SerializObject();
|
|
||||||
instanceObject.Type = type;
|
|
||||||
instanceObject.ArrayType = type.GetElementType();
|
|
||||||
instanceObject.instanceType = InstanceType.Array;
|
|
||||||
return instanceObject;
|
|
||||||
}));
|
|
||||||
return typeInfo;
|
|
||||||
}
|
|
||||||
else if (type.IsClass || type.IsStruct())
|
|
||||||
{
|
|
||||||
if (type.IsNullableType())
|
|
||||||
{
|
|
||||||
type = type.GetGenericArguments()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializObject serializObject = InstanceCache.GetOrAdd(type.FullName, (v) =>
|
|
||||||
{
|
|
||||||
SerializObject instanceObject = new SerializObject();
|
|
||||||
instanceObject.Type = type;
|
|
||||||
if (type.IsGenericType)
|
|
||||||
{
|
|
||||||
instanceObject.AddMethod = new Method(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 (RRQMCoreUtility.listType.IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
while (!baseType.IsGenericType)
|
|
||||||
{
|
|
||||||
baseType = baseType.BaseType;
|
|
||||||
}
|
|
||||||
instanceObject.ArgTypes = baseType.GetGenericArguments();
|
|
||||||
|
|
||||||
instanceObject.AddMethod = new Reflection.Method(type.GetMethod("Add"));
|
|
||||||
instanceObject.instanceType = InstanceType.List;
|
|
||||||
}
|
|
||||||
else if (RRQMCoreUtility.dicType.IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
Type baseType = type.BaseType;
|
|
||||||
while (!baseType.IsGenericType)
|
|
||||||
{
|
|
||||||
baseType = baseType.BaseType;
|
|
||||||
}
|
|
||||||
instanceObject.ArgTypes = baseType.GetGenericArguments();
|
|
||||||
instanceObject.AddMethod = new Reflection.Method(type.GetMethod("Add"));
|
|
||||||
instanceObject.instanceType = InstanceType.Dictionary;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
instanceObject.Properties = GetProperties(type).ToDictionary(a=>a.Name);
|
|
||||||
instanceObject.instanceType = InstanceType.Class;
|
|
||||||
}
|
|
||||||
return instanceObject;
|
|
||||||
});
|
|
||||||
return serializObject;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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.Reflection;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace RRQMCore.Serialization
|
|
||||||
{
|
|
||||||
class SerializObject
|
|
||||||
{
|
|
||||||
public InstanceType instanceType;
|
|
||||||
public Type Type;
|
|
||||||
|
|
||||||
public object GetInstance()
|
|
||||||
{
|
|
||||||
return Activator.CreateInstance(this.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type[] ArgTypes;
|
|
||||||
public Type ArrayType;
|
|
||||||
public Dictionary<string,PropertyInfo>Properties;
|
|
||||||
public Method AddMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,379 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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序列化和反序列化
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,871 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,553 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,271 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// 此代码版权(除特别声明或在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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user