diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..f0012cd20b9e0f756d08140b20a4ffdcaef00c29
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,217 @@
+# 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行
+root = true
+
+# c# 文件
+[*.cs]
+
+#### Core EditorConfig 选项 ####
+
+# 缩进和间距
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# 新行首选项
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET 编码约定 ####
+
+# 组织 Using
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = false
+file_header_template = unset
+
+# this. 和 Me. 首选项
+dotnet_style_qualification_for_event = false
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false
+dotnet_style_qualification_for_property = false
+
+# 语言关键字与 bcl 类型首选项
+dotnet_style_predefined_type_for_locals_parameters_members = true
+dotnet_style_predefined_type_for_member_access = true
+
+# 括号首选项
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
+
+# 修饰符首选项
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# 表达式级首选项
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true
+dotnet_style_explicit_tuple_names = true
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true
+dotnet_style_prefer_compound_assignment = true
+dotnet_style_prefer_conditional_expression_over_assignment = true
+dotnet_style_prefer_conditional_expression_over_return = true
+dotnet_style_prefer_inferred_anonymous_type_member_names = true
+dotnet_style_prefer_inferred_tuple_names = true
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error
+dotnet_style_prefer_simplified_boolean_expressions = true
+dotnet_style_prefer_simplified_interpolation = true
+
+# 字段首选项
+dotnet_style_readonly_field = true
+
+# 参数首选项
+dotnet_code_quality_unused_parameters = all
+
+# 禁止显示首选项
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# 新行首选项
+dotnet_style_allow_multiple_blank_lines_experimental = true
+dotnet_style_allow_statement_immediately_after_block_experimental = true
+
+#### c# 编码约定 ####
+
+# var 首选项
+csharp_style_var_elsewhere = false
+csharp_style_var_for_built_in_types = false
+csharp_style_var_when_type_is_apparent = false
+
+# Expression-bodied 成员
+csharp_style_expression_bodied_accessors = true
+csharp_style_expression_bodied_constructors = false
+csharp_style_expression_bodied_indexers = true
+csharp_style_expression_bodied_lambdas = true
+csharp_style_expression_bodied_local_functions = false
+csharp_style_expression_bodied_methods = false
+csharp_style_expression_bodied_operators = false
+csharp_style_expression_bodied_properties = true
+
+# 模式匹配首选项
+csharp_style_pattern_matching_over_as_with_null_check = true
+csharp_style_pattern_matching_over_is_with_cast_check = true
+csharp_style_prefer_not_pattern = true
+csharp_style_prefer_pattern_matching = true
+csharp_style_prefer_switch_expression = true
+
+# Null 检查首选项
+csharp_style_conditional_delegate_call = true
+
+# 修饰符首选项
+csharp_prefer_static_local_function = true
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
+
+# 代码块首选项
+csharp_prefer_braces = true
+csharp_prefer_simple_using_statement = true
+
+# 表达式级首选项
+csharp_prefer_simple_default_expression = true
+csharp_style_deconstructed_variable_declaration = true
+csharp_style_implicit_object_creation_when_type_is_apparent = true
+csharp_style_inlined_variable_declaration = true
+csharp_style_pattern_local_over_anonymous_function = true
+csharp_style_prefer_index_operator = true
+csharp_style_prefer_range_operator = true
+csharp_style_throw_expression = true
+csharp_style_unused_value_assignment_preference = discard_variable
+csharp_style_unused_value_expression_statement_preference = discard_variable
+
+# "using" 指令首选项
+csharp_using_directive_placement = outside_namespace
+
+# 新行首选项
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
+csharp_style_allow_embedded_statements_on_same_line_experimental = true
+
+#### C# 格式规则 ####
+
+# 新行首选项
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = accessors,anonymous_methods,anonymous_types,control_blocks,methods,object_collection_array_initializers,properties,types
+csharp_new_line_between_query_expression_clauses = true
+
+# 缩进首选项
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# 空格键首选项
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# 包装首选项
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#### 命名样式 ####
+
+# 命名规则
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# 符号规范
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# 命名样式
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
diff --git a/.gitignore b/.gitignore
index faf876255f879578e1407606fc89f5473b4d3eee..e910608fc1ecabe29cb4e88eeab0a35a2b752e7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -398,3 +398,13 @@ ASALocalRun/
# BeatPulse healthcheck temp database
# BeatPulse healthcheck ʱݿ
healthchecksdb
+
+#macos
+*.DS_Store
+
+#vscode
+.ionide
+.vscode
+
+#ifoxcad
+#tests/TestConsole/
\ No newline at end of file
diff --git a/IFoxCAD.sln b/IFoxCAD.sln
index 309172c25fb1b97b8272542e4f372dffa18487a9..aef47062b5aab5537f54dc126d817007bd47748a 100644
--- a/IFoxCAD.sln
+++ b/IFoxCAD.sln
@@ -1,15 +1,27 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31025.194
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.32113.165
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Cad", "src\IFoxCAD.Cad\IFoxCAD.Cad.csproj", "{D5FAED7C-A99B-4BEE-A745-45442DC44971}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DBTrans.test", "tests\DBTrans.test\DBTrans.test.csproj", "{B1602568-F023-46C7-B635-3CB281F1EC00}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "tests\Test\Test.csproj", "{B1602568-F023-46C7-B635-3CB281F1EC00}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.WPF", "src\IFoxCAD.WPF\IFoxCAD.WPF.csproj", "{D820D629-1AB3-4BE3-A772-CB753D98CCB8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IFoxCAD.Basal", "src\IFoxCAD.Basal\IFoxCAD.Basal.csproj", "{40BF07C4-100A-4810-A27B-4587CFB38E6E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Basal", "src\IFoxCAD.Basal\IFoxCAD.Basal.csproj", "{40BF07C4-100A-4810-A27B-4587CFB38E6E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestConsole", "tests\TestConsole\TestConsole.csproj", "{E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Gcad", "src\IFoxCAD.Cad\IFoxCAD.Gcad.csproj", "{D7756AF6-601D-40C2-97E9-940E5AFC2E08}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "IFoxCAD.Cad.Shared", "src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.shproj", "{82FB8450-B971-4E30-859F-4B2DDB81F590}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cad", "Cad", "{465C4E39-FBA2-417A-AB31-BDC01601F420}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Acad08", "src\IFoxCAD.Cad\IFoxCAD.Acad08.csproj", "{F5C0DA54-2031-436D-B6FA-03C745B98862}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Acad09plus", "src\IFoxCAD.Cad\IFoxCAD.Acad09plus.csproj", "{34213E53-C0F5-49DF-9FB2-0A5D861013EF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.ZWcad", "src\IFoxCAD.Cad\IFoxCAD.ZWcad.csproj", "{C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -17,10 +29,6 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {D5FAED7C-A99B-4BEE-A745-45442DC44971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D5FAED7C-A99B-4BEE-A745-45442DC44971}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D5FAED7C-A99B-4BEE-A745-45442DC44971}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D5FAED7C-A99B-4BEE-A745-45442DC44971}.Release|Any CPU.Build.0 = Release|Any CPU
{B1602568-F023-46C7-B635-3CB281F1EC00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1602568-F023-46C7-B635-3CB281F1EC00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1602568-F023-46C7-B635-3CB281F1EC00}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -33,11 +41,45 @@ Global
{40BF07C4-100A-4810-A27B-4587CFB38E6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{40BF07C4-100A-4810-A27B-4587CFB38E6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{40BF07C4-100A-4810-A27B-4587CFB38E6E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D7756AF6-601D-40C2-97E9-940E5AFC2E08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D7756AF6-601D-40C2-97E9-940E5AFC2E08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D7756AF6-601D-40C2-97E9-940E5AFC2E08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D7756AF6-601D-40C2-97E9-940E5AFC2E08}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F5C0DA54-2031-436D-B6FA-03C745B98862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F5C0DA54-2031-436D-B6FA-03C745B98862}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F5C0DA54-2031-436D-B6FA-03C745B98862}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F5C0DA54-2031-436D-B6FA-03C745B98862}.Release|Any CPU.Build.0 = Release|Any CPU
+ {34213E53-C0F5-49DF-9FB2-0A5D861013EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {34213E53-C0F5-49DF-9FB2-0A5D861013EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {34213E53-C0F5-49DF-9FB2-0A5D861013EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {34213E53-C0F5-49DF-9FB2-0A5D861013EF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {D7756AF6-601D-40C2-97E9-940E5AFC2E08} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {82FB8450-B971-4E30-859F-4B2DDB81F590} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {F5C0DA54-2031-436D-B6FA-03C745B98862} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {34213E53-C0F5-49DF-9FB2-0A5D861013EF} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {C6FC723B-B4CD-475A-BBA7-4FE5CE82AC5A} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31D6C754-CF6B-4AB0-9861-6923DD312350}
EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{34213e53-c0f5-49df-9fb2-0a5d861013ef}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{82fb8450-b971-4e30-859f-4b2ddb81f590}*SharedItemsImports = 13
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{c6fc723b-b4cd-475a-bba7-4fe5ce82ac5a}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{d7756af6-601d-40c2-97e9-940e5afc2e08}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{f5c0da54-2031-436d-b6fa-03c745b98862}*SharedItemsImports = 5
+ EndGlobalSection
EndGlobal
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index 7c3d2c4742185f4b8d6f8b3319a78c74079f6822..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# IFoxCAD
-
-#### Description
-基于.NET的Cad二次开发类库
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
index f3128878b0a67fb90c186c1e8f9c8465f55e6a77..6a4b01206b7202cb55453f20c3058baabaeab5bc 100644
--- a/README.md
+++ b/README.md
@@ -2,53 +2,90 @@
#### 介绍
-基于.NET的Cad二次开发类库
+基于.NET的Cad二次开发类库。
+
+可以加群交流:
+
+
#### 软件架构及相关说明
- [软件架构说明](/docs/关于IFoxCAD的架构说明.md)
-
- [扩展函数说明](/docs/关于扩展函数的说明.md)
-#### 安装教程
+#### 编译 IFox 源码工程
-1. vs新建net standord 类库
-2. 修改项目TargetFramework为net45,保存重加载项目
-3. 右键项目,管理nuget程序包,搜索ifoxcad,安装最新版就可以了
+由于vs2022抛弃了某几个net版本,所以我们同时安装vs2019和vs2022,然后使用vs2022;
+其中的原因是vs2019拥有全部net版本,而vs2022拥有最新的分析器和语法.
-#### 使用说明
+#### IFoxCad 项目模版
-1. 快速入门
+可以在vs扩展菜单-管理扩展中搜索ifoxcad,即可安装项目模板。使用项目模版可以方便的创建支持多目标多版本的使用ifoxcad类库的项目和类。如果无法在vs的市场里下载,就去上面的QQ群里下载。
- - 打开vs,新建一个standard类型的类库项目,修改项目文件里的`netcore2.0`为`NET45`。其中的net45,可以改为NET35以上的标准TFM(如:net35、net40、net45、net46、net47等等)。同时可以指定多版本。具体的详细的教程见 [VS通过添加不同引用库,建立多条件编译]( https://www.yuque.com/vicwjb/zqpcd0/ufbwyl)。
- - 右键项目文件,选择管理nuget程序包。
- - 在nuget程序里搜索**ifoxcad**,直接选择最新的版本,然后点击安装**IFoxCAD.Cad**,nuget会自动安装ifoxcad依赖的库。
- - 添加引用
+#### 安装教程
- ```c#
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Runtime;
- using Autodesk.AutoCAD.Geometry;
- using Autodesk.AutoCAD.DatabaseServices;
- using IFoxCAD.Cad;
- ```
+1. 新建net standard 类库
+2. 修改项目`.csproj`的`TargetFrameworks`为net45,保存重加载项目,这里需要注意和cad版本对照.
+3. 右键项目,管理nuget程序包,搜索ifoxcad,安装最新版就可以了.
- - 添加代码
+#### 使用说明
- ```c#
- [CommandMethod("hello")]
- public void Hello()
- {
- using var tr = new DBTrans()
- var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0));
- tr.CurrentSpace.AddEntity(line1);
- }
+1. 快速入门
+
+ - 打开vs,新建一个standard类型的类库项目,**注意,需要选择类型的时候一定要选standard2.0** 
+
+ - 双击项目,打开项目文件:
+
+ - 修改项目文件里的`netcore2.0`为`NET45`。其中的net45,可以改为NET45以上的标准TFM(如:net45、net46、net47等等)。同时可以指定多版本。具体的详细的教程见 [VS通过添加不同引用库,建立多条件编译]( https://www.yuque.com/vicwjb/zqpcd0/ufbwyl)。
+
+ - 在 ` xxx ` 中增加 `preview`,主要是为了支持最新的语法,本项目采用了最新的语法编写。项目文件现在的内容类似如下:
+
+ ```xml
+
+
+ net45
+ preview
+
+
```
-
- 这段代码就是在cad的当前空间内添加了一条直线。
-
+
+ - 右键项目文件,选择管理nuget程序包。
+
+ - 在nuget程序里搜索**ifoxcad**,直接选择最新的版本(如果你是 **net40** 或者 **net35** 的用户,可以安装 **0.1.6** 版本),然后点击安装**IFoxCAD.Cad**,nuget会自动安装ifoxcad依赖的库。(按下图绿色框框里选择浏览,程序包来源选择nuget.org,安装IFoxCAD.Cad包。IFoxCAD.Basal是IFoxCAD.Cad的依赖项会自动安装,如果要开发wpf界面的话,可以安装IFoxCAD.WPF,提供了简单的mvvm支持)
+
+ - 添加引用
+
+ ```c#
+ using Autodesk.AutoCAD.ApplicationServices;
+ using Autodesk.AutoCAD.EditorInput;
+ using Autodesk.AutoCAD.Runtime;
+ using Autodesk.AutoCAD.Geometry;
+ using Autodesk.AutoCAD.DatabaseServices;
+ using IFoxCAD.Cad;
+ ```
+
+ - 添加代码
+
+ ```c#
+ [CommandMethod("hello")]
+ public void Hello()
+ {
+ using var tr = new DBTrans();
+ var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0));
+ tr.CurrentSpace.AddEntity(line1);
+ // 如果你没有添加preview到项目文件里的话:按如下旧语法:
+ // using(var tr = new DBTrans())
+ // {
+ // var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0));
+ // tr.CurrentSpace.AddEntity(line1);
+ // }
+ }
+ ```
+
+ 这段代码就是在cad的当前空间内添加了一条直线。
+
- F6生成,然后打开cad,netload命令将刚刚生成的dll加载。
+
- 运行hello命令,然后缩放一下视图,现在一条直线和一个圆已经显示在屏幕上了。
2. [事务管理器用法](/docs/DBTrans.md)
@@ -60,23 +97,62 @@
5. [WPF支持](/docs/WPF.md)
6. 天秀的自动加载与初始化
-
- 为了将程序集的初始化和通过写注册表的方式实现自动加载统一设置,减少每次重复的工作量,内裤提供了`AutoRegAssem`抽象类来完成此功能,只要在需要初始化的类继承`AutoRegAssem`类,然后实现`Initialize()` 和`Terminate()`两个函数就可以了。特别强调的是,一个程序集里只能有一个类继承,不管是不是同一个命名空间。
-
+
+ 为了将程序集的初始化和通过写注册表的方式实现自动加载统一设置,减少每次重复的工作量,类裤提供了`AutoRegAssem`抽象类来完成此功能,只要在需要初始化的类继承`AutoRegAssem`类,然后实现`Initialize()` 和`Terminate()`两个函数就可以了。
+ 特别强调的是,一个程序集里只能有一个类继承,不管是不是同一个命名空间。
+
+ 但是为了满足开闭原则,使用特性进行分段初始化是目前最佳选择
+
```c#
- public class Test : AutoRegAssem //继承
+ using Autodesk.AutoCAD.Runtime;
+ using IFoxCAD.Cad;
+ using System;
+ using System.Reflection;
+
+ /*
+ * 自动执行接口
+ * 这里必须要实现一次这个接口,才能使用 IFoxInitialize 特性进行自动执行
+ */
+ public class CmdINI : AutoRegAssem
{
- public override void Initialize() //实现接口函数
- {
- throw new NotImplementedException();
+ // 这里可以写任何普通的函数,也可以写下面 AutoTest 类里的实现了 IFoxInitialize 特性的初始化函数
+ // 继承AutoRegAssem的主要作用是写注册表用来自动加载dll,同时执行实现了 IFoxInitialize 特性的函数
+ // 注意这里的自动执行是在cad启动后,加载了dll之后执行,而不是运行命令后执行。
+
+ [IFoxInitialize]
+ public void InitOne()
+ {
+ //TODO 你想在加载dll之后自动执行的函数
+ // 可以随便在哪里类里 可以多次实现 IFoxInitialize 特性
}
- public override void Terminate() //实现接口函数
+
+ }
+
+ //其他的类中的函数:
+ //实现自动接口之后,在任意一个函数上面使用此特性,减少每次改动 CmdINI 类
+ public class AutoTest
+ {
+ [IFoxInitialize]
+ public void Initialize()
+ {
+ //TODO 你想在加载dll之后自动执行的函数
+ }
+ [IFoxInitialize]
+ public void InitTwo()
+ {
+ //TODO 你想在加载dll之后自动执行的函数
+ // 可以随便在哪里类里 可以多次实现 IFoxInitialize 特性
+ }
+ [IFoxInitialize(isInitialize: false)] // 特性的参数为false的时候就表示卸载时执行的函数
+ public void Terminate()
{
- throw new NotImplementedException();
+ //TODO 你想在关闭cad时自动执行的函数
}
}
```
-
+
+
+
7. 天秀的打开模式提权
由于cad的对象是有打开模式,是否可写等等,为了安全起见,在处理对象时,一般是用读模式打开,然后需要写数据的时候在提权为写模式,然后在降级到读模式,但是这个过程中,很容易漏掉某些步骤,然后cad崩溃。为了处理这些情况,内裤提供了提权类来保证读写模式的有序转换。
@@ -88,4 +164,5 @@
} //关闭事务自动处理读写模式
```
-8. 未完待续。。。。
\ No newline at end of file
+8. 未完待续。。。。
+
diff --git a/docs/DBTrans.md b/docs/DBTrans.md
index 29f88dc34efd118c229cbf052524c672e127c5dd..5e758600d98ae015c0306c2070a3ddffe301bf3d 100644
--- a/docs/DBTrans.md
+++ b/docs/DBTrans.md
@@ -59,7 +59,7 @@ using (DBTrans tr = new DBTrans()) // 第一步,开启事务
- **向符号表里添加元素**
```c#
- using (DBTransaction tr = new DBTransaction())
+ using (DBTrans tr = new DBTrans())
{ // 第一步,开启事务
var layerTable = tr.LayerTable;
// 第二步,获取图层表
@@ -75,7 +75,7 @@ using (DBTrans tr = new DBTrans()) // 第一步,开启事务
想要添加和获取符号表内的某个元素非常的简单:
```c#
- using (DBTransaction tr = new DBTransaction()) // 第一步,开启事务
+ using (DBTrans tr = new DBTrans()) // 第一步,开启事务
{
var layerTable = tr.LayerTable; // 第二步,获取图层表
layerTable.Add("1"); // 第三步,添加名为“1”的图层,即新建图层
diff --git a/docs/WPF.md b/docs/WPF.md
index 08d7c28c998bb6de4a1ef40db96a0110928ae9a0..73f4f1116be4ef9cff68117b0f2fd86acf32d382 100644
--- a/docs/WPF.md
+++ b/docs/WPF.md
@@ -225,7 +225,7 @@ public class TestViewModel : ViewModelBase
首先是在xaml里引入命名空间。
-`xmlns:eb="clr-namespace:IFoxCad.WPF;assembly=IFoxCad"`
+`xmlns:eb="clr-namespace:IFoxCAD.WPF;assembly=IFoxCAD.WPF"`
然后
diff --git "a/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" "b/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png"
new file mode 100644
index 0000000000000000000000000000000000000000..a9d08c483b80f21d4b0ac6a0afe80f9b6b4233e6
Binary files /dev/null and "b/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" differ
diff --git a/docs/png/nuget.png b/docs/png/nuget.png
new file mode 100644
index 0000000000000000000000000000000000000000..d0af980fedd9eca39d0e0bf787111685242994ac
Binary files /dev/null and b/docs/png/nuget.png differ
diff --git a/docs/png/nuget1.png b/docs/png/nuget1.png
new file mode 100644
index 0000000000000000000000000000000000000000..91983ffef3b246ea796296b14fe09963663de184
Binary files /dev/null and b/docs/png/nuget1.png differ
diff --git a/docs/png/standard.png b/docs/png/standard.png
new file mode 100644
index 0000000000000000000000000000000000000000..dfc34fecb32120f54436115208a4abaea2dac516
Binary files /dev/null and b/docs/png/standard.png differ
diff --git "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
index d8282200a6734c08bfbb1b74d08845f5806f51e9..69a9b7908a8b9e873448ef124344ebfc73bb4878 100644
--- "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
+++ "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
@@ -7,10 +7,10 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核
## 一、组织结构图
- IFoxCAD
- - IFoxCAD.Cad - cad相关的类库
+ - IFoxCAD.Basal - cad以外常用的类库
- LinqEx - linq扩展类
- LoopList - 环链表
- - IFoxCAD.Basal - cad以外常用的类库
+ - IFoxCAD.Cad - cad相关的类库
- Runtime - 包含系统级别的功能
- AcadVersion - cad版本号类
- AssemInfo - 程序集信息
@@ -45,7 +45,7 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核
### 2.2 关于DBTrans类的具体构成元素的意义
-DBTrans类里基本的封装就是Transaction,然后是Document、Database、Editor、符号表、命名字典等,而抓这些其实都是cad二次开发关于图元操作经常打交道的概念。
+DBTrans类里基本的封装就是Transaction,然后是Document、Database、Editor、符号表、命名字典等,而这些其实都是cad二次开发关于图元操作经常打交道的概念。
DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的相关类库,通过这些属性就可以对数据进行相应的操作。特别是符号表中最常用的就是块表,通过对块表的操作来实现添加图元等。
@@ -109,7 +109,7 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的
- Has --- 判断符号表是否有符号表记录的函数
- 。。。
-特殊说明:当符号表为块表时,上述函数实际操作的是块定义、属性定义等。所以为了添加图元,需要特殊写法。
+特殊说明:当符号表为块表时,上述函数实际操作的是块定义、属性定义等。所以为了添加图元,需要特殊写法,原因在于cad的实体都是存在符号表记录里的,通常为模型这个块表记录。
# 慢慢完善,想到哪写到哪。。。
diff --git a/src/IFoxCAD.Basal/ArrayEx.cs b/src/IFoxCAD.Basal/ArrayEx.cs
new file mode 100644
index 0000000000000000000000000000000000000000..34fb4b7543550facad7f49d996336cee6e73b541
--- /dev/null
+++ b/src/IFoxCAD.Basal/ArrayEx.cs
@@ -0,0 +1,50 @@
+namespace IFoxCAD.Basal
+{
+ /*
+ * 由于linq的函数大部分带有状态机,而cad是一个单机程序,
+ * 使用状态机会变得缓慢,因此我们设计的时候着重于时间优化,
+ * 本工具类在着重于数组遍历时候替代linq
+ */
+ public static class ArrayEx
+ {
+ ///
+ /// 合并数组
+ ///
+ ///
+ ///
+ public static T[] Combine2(this T[] a, T[] b)
+ {
+ var c = new T[a.Length + b.Length];
+ Array.Copy(a, 0, c, 0, a.Length);
+ Array.Copy(b, 0, c, a.Length, b.Length);
+ return c;
+ }
+
+ ///
+ /// 一维数组消重,此函数建议更改为:
+ /// set = new();
+ /// foreach (var item in listInOut)
+ /// set.Add(item);
+ /// ]]>
+ ///
+ ///
+ /// 传入有重复成员的数组,传出没有重复的
+ /// 传出参数1:数组开头;传出参数2:数组结尾;返回值比较结尾为就移除
+ [Obsolete]
+ public static void Deduplication(List listInOut, Func func)
+ {
+ for (int i = 0; i < listInOut.Count; i++)
+ {
+ var first = listInOut[i];
+ for (int j = listInOut.Count - 1; j > i; j--)
+ {
+ var last = listInOut[j];
+ if (func(first, last))
+ listInOut.RemoveAt(j);
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/IFoxCAD.Basal/CLS/Index.cs b/src/IFoxCAD.Basal/CLS/Index.cs
new file mode 100644
index 0000000000000000000000000000000000000000..97b51e5dbc5fe497942c1a8aa6a7c7d4504ffb78
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/Index.cs
@@ -0,0 +1,148 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System;
+
+using System.Runtime.CompilerServices;
+
+/// Represent a type can be used to index a collection either from the start or the end.
+///
+/// Index is used by the C# compiler to support the new index syntax
+///
+/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
+/// int lastElement = someArray[^1]; // lastElement = 5
+///
+///
+public readonly struct Index : IEquatable
+{
+ private readonly int _value;
+
+ /// Construct an Index using a value and indicating if the index is from the start or from the end.
+ /// The index value. it has to be zero or positive number.
+ /// Indicating if the index is from the start or from the end.
+ ///
+ /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
+ ///
+#if NET45
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ public Index(int value, bool fromEnd = false)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
+ }
+
+ if (fromEnd)
+ _value = ~value;
+ else
+ _value = value;
+ }
+
+ // The following private constructors mainly created for perf reason to avoid the checks
+ private Index(int value)
+ {
+ _value = value;
+ }
+
+ /// Create an Index pointing at first element.
+ public static Index Start => new(0);
+
+ /// Create an Index pointing at beyond last element.
+ public static Index End => new(~0);
+
+ /// Create an Index from the start at the position indicated by the value.
+ /// The index value from the start.
+#if NET45
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ public static Index FromStart(int value)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
+ }
+
+ return new Index(value);
+ }
+
+ /// Create an Index from the end at the position indicated by the value.
+ /// The index value from the end.
+#if NET45
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ public static Index FromEnd(int value)
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
+ }
+
+ return new Index(~value);
+ }
+
+ /// Returns the index value.
+ public int Value
+ {
+ get
+ {
+ if (_value < 0)
+ return ~_value;
+ else
+ return _value;
+ }
+ }
+
+ /// Indicates whether the index is from the start or the end.
+ public bool IsFromEnd => _value < 0;
+
+ /// Calculate the offset from the start using the giving collection length.
+ /// The length of the collection that the Index will be used with. length has to be a positive value
+ ///
+ /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
+ /// we don't validate either the returned offset is greater than the input length.
+ /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
+ /// then used to index a collection will get out of range exception which will be same affect as the validation.
+ ///
+#if NET45
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ public int GetOffset(int length)
+ {
+ int offset = _value;
+ if (IsFromEnd)
+ {
+ // offset = length - (~value)
+ // offset = length + (~(~value) + 1)
+ // offset = length + value + 1
+
+ offset += length + 1;
+ }
+ return offset;
+ }
+
+ /// Indicates whether the current Index object is equal to another object of the same type.
+ /// An object to compare with this object
+ public override bool Equals(object? value) => value is Index index && _value == index._value;
+
+ /// Indicates whether the current Index object is equal to another Index object.
+ /// An object to compare with this object
+ public bool Equals(Index other) => _value == other._value;
+
+ /// Returns the hash code for this instance.
+ public override int GetHashCode() => _value;
+
+ /// Converts integer number to an Index.
+ public static implicit operator Index(int value) => FromStart(value);
+
+ /// Converts the value of the current Index object to its equivalent string representation.
+ public override string ToString()
+ {
+ if (IsFromEnd)
+ return "^" + ((uint)Value).ToString();
+
+ return ((uint)Value).ToString();
+ }
+}
+
diff --git a/src/IFoxCAD.Basal/CLS/Range.cs b/src/IFoxCAD.Basal/CLS/Range.cs
new file mode 100644
index 0000000000000000000000000000000000000000..221167b3559504513705f4613bd4a6dc707dbacc
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/Range.cs
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System;
+
+using System.Runtime.CompilerServices;
+
+
+/// Represent a range has start and end indexes.
+///
+/// Range is used by the C# compiler to support the range syntax.
+///
+/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
+/// int[] subArray1 = someArray[0..2]; // { 1, 2 }
+/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
+///
+///
+public readonly struct Range : IEquatable
+{
+ /// Represent the inclusive start index of the Range.
+ public Index Start { get; }
+
+ /// Represent the exclusive end index of the Range.
+ public Index End { get; }
+
+ /// Construct a Range object using the start and end indexes.
+ /// Represent the inclusive start index of the range.
+ /// Represent the exclusive end index of the range.
+ public Range(Index start, Index end)
+ {
+ Start = start;
+ End = end;
+ }
+
+ /// Indicates whether the current Range object is equal to another object of the same type.
+ /// An object to compare with this object
+ public override bool Equals(object? value) =>
+ value is Range r &&
+ r.Start.Equals(Start) &&
+ r.End.Equals(End);
+
+ /// Indicates whether the current Range object is equal to another Range object.
+ /// An object to compare with this object
+ public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End);
+
+ /// Returns the hash code for this instance.
+ public override int GetHashCode()
+ {
+ return Start.GetHashCode() * 31 + End.GetHashCode();
+ }
+
+ /// Converts the value of the current Range object to its equivalent string representation.
+ public override string ToString()
+ {
+ return Start + ".." + End;
+ }
+
+ /// Create a Range object starting from start index to the end of the collection.
+ public static Range StartAt(Index start) => new(start, Index.End);
+
+ /// Create a Range object starting from first element in the collection to the end Index.
+ public static Range EndAt(Index end) => new(Index.Start, end);
+
+ /// Create a Range object starting from first element to the end.
+ public static Range All => new(Index.Start, Index.End);
+
+ /// Calculate the start offset and length of range object using a collection length.
+ /// The length of the collection that the range will be used with. length has to be a positive value.
+ ///
+ /// For performance reason, we don't validate the input length parameter against negative values.
+ /// It is expected Range will be used with collections which always have non negative length/count.
+ /// We validate the range is inside the length scope though.
+ ///
+#if NET45
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+ //[CLSCompliant(false)]
+ public (int Offset, int Length) GetOffsetAndLength(int length)
+ {
+ int start;
+ Index startIndex = Start;
+ if (startIndex.IsFromEnd)
+ start = length - startIndex.Value;
+ else
+ start = startIndex.Value;
+
+ int end;
+ Index endIndex = End;
+ if (endIndex.IsFromEnd)
+ end = length - endIndex.Value;
+ else
+ end = endIndex.Value;
+
+ if ((uint)end > (uint)length || (uint)start > (uint)end)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length));
+ }
+
+ return (start, end - start);
+ }
+}
+
diff --git a/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs b/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a446c591297319b41b097188f0a62fcb017dddb3
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs
@@ -0,0 +1,44 @@
+//#if NET35
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Runtime.CompilerServices;
+
+public static class RuntimeHelpers
+{
+ ///
+ /// Slices the specified array using the specified range.
+ ///
+ public static T[] GetSubArray(T[] array, Range range)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ (int offset, int length) = range.GetOffsetAndLength(array.Length);
+
+ if (default(T)! != null || typeof(T[]) == array.GetType()) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
+ {
+ // We know the type of the array to be exactly T[].
+ if (length == 0)
+ {
+ //return Array.Empty();
+ return new T[0];
+ }
+
+ var dest = new T[length];
+ Array.Copy(array, offset, dest, 0, length);
+ return dest;
+ }
+ else
+ {
+ // The array is actually a U[] where U:T.
+ T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length);
+ Array.Copy(array, offset, dest, 0, length);
+ return dest;
+ }
+ }
+
+
+}
+//#endif
\ No newline at end of file
diff --git a/src/IFoxCAD.Basal/CLS/TupleElementNamesAttribute.cs b/src/IFoxCAD.Basal/CLS/TupleElementNamesAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69670b464b44ed16d9fca6eaa01c0227e00f6815
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/TupleElementNamesAttribute.cs
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using IFoxCAD.Basal;
+
+namespace System.Runtime.CompilerServices;
+
+///
+/// Indicates that the use of on a member is meant to be treated as a tuple with element names.
+///
+[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Event)]
+public sealed class TupleElementNamesAttribute : Attribute
+{
+ private readonly string[] _transformNames;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Specifies, in a pre-order depth-first traversal of a type's
+ /// construction, which occurrences are
+ /// meant to carry element names.
+ ///
+ ///
+ /// This constructor is meant to be used on types that contain an
+ /// instantiation of that contains
+ /// element names. For instance, if C is a generic type with
+ /// two type parameters, then a use of the constructed type C{, might be intended to
+ /// treat the first type argument as a tuple with element names and the
+ /// second as a tuple without element names. In which case, the
+ /// appropriate attribute specification should use a
+ /// transformNames value of { "name1", "name2", null, null,
+ /// null }.
+ ///
+ public TupleElementNamesAttribute(string[] transformNames)
+ {
+ if (transformNames == null)
+ throw new ArgumentNullException(nameof(transformNames));
+
+ _transformNames = transformNames;
+ }
+
+ ///
+ /// Specifies, in a pre-order depth-first traversal of a type's
+ /// construction, which elements are
+ /// meant to carry element names.
+ ///
+ public IList TransformNames => _transformNames;
+}
\ No newline at end of file
diff --git a/src/IFoxCAD.Basal/CLS/ValueTuple.cs b/src/IFoxCAD.Basal/CLS/ValueTuple.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bece1ed60c6bf866a43cb92a6af6a2cf571a5910
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/ValueTuple.cs
@@ -0,0 +1,2144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//#pragma warning disable SA1141 // explicitly not using tuple syntax in tuple implementation
+
+
+using System.Diagnostics;
+using System.Numerics.Hashing;
+/*
+ * 惊惊:
+ * 首先是因为有人想要编译的时候只形成一个dll,然后把元组塞入IFox,同时也补充了net35没有元组的遗憾.
+ * 而利用nuget元组包必然会形成依赖地狱.
+ *
+ * 如果你的工程使用了nuget元组包,就造成了必须要剔除IFox.
+ *
+ * 改IFox的元组命名空间倒是可以分离两者,但是 vs编译器 无法识别带其他命名空间的元组.
+ * 所以元组本身就是冲突的,需要把其他元组卸载掉,由IFox提供.
+ */
+
+#if NET35
+namespace System.Collections
+{
+ public interface IStructuralComparable
+ {
+ int CompareTo(object? other, IComparer comparer);
+ }
+ public interface IStructuralEquatable
+ {
+ bool Equals(object? other, IEqualityComparer comparer);
+ int GetHashCode(IEqualityComparer comparer);
+ }
+}
+#endif
+
+
+
+namespace System.Numerics.Hashing
+{
+ internal static class HashHelpers
+ {
+ public static readonly int RandomSeed = Guid.NewGuid().GetHashCode();
+
+ public static int Combine(int h1, int h2)
+ {
+ unchecked
+ {
+ // RyuJIT optimizes this to use the ROL instruction
+ // Related GitHub pull request: dotnet/coreclr#1830
+
+ // RyuJIT 对此进行了优化以使用 ROL 指令
+ // 相关 GitHub 拉取请求:dotnet/coreclr#1830
+ uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
+ return ((int)rol5 + h1) ^ h2;
+ }
+ }
+ }
+}
+
+
+
+
+namespace System
+{
+ //internal static class SR
+ internal sealed partial class SR
+ {
+ // public const string ArgumentException_ValueTupleIncorrectType = "The parameter should be a ValueTuple type of appropriate arity.";
+ // public const string ArgumentException_ValueTupleLastArgumentNotAValueTuple = "The TRest type argument of ValueTuple`8 must be a ValueTuple.";
+ public const string ArgumentException_ValueTupleIncorrectType = "该参数应该是适当数量的 ValueTuple 类型.";
+ public const string ArgumentException_ValueTupleLastArgumentNotAValueTuple = "ValueTuple`8 的 TREST 类型参数必须是 ValueTuple.";
+ }
+
+ // Helper so we can call some tuple methods recursively without knowing the underlying types.
+ ///
+ /// 帮助器,因此我们可以在不知道底层类型的情况下递归调用一些元组方法.
+ ///
+ internal interface ITupleInternal
+ {
+ int GetHashCode(IEqualityComparer comparer);
+ int Size { get; }
+ string ToStringEnd();
+ }
+
+
+ // The ValueTuple types (from arity 0 to 8) comprise the runtime implementation that underlies tuples in C# and struct tuples in F#.
+ // Aside from created via language syntax, they are most easily created via the ValueTuple.Create factory methods.
+ // The System.ValueTuple types differ from the System.Tuple types in that:
+ // - they are structs rather than classes,
+ // - they are mutable rather than readonly, and
+ // - their members (such as Item1, Item2, etc) are fields rather than properties.
+ ///
+ /// ValueTuple 类型(从 arity 0 到 8)包含运行时实现,它是 C# 中的元组和 F# 中的结构元组的基础.
+ /// 除了通过语言语法创建之外,它们最容易通过 ValueTuple.Create 工厂方法创建.
+ /// System.ValueTuple 类型与 System.Tuple 类型的不同之处在于:
+ /// - 它们是结构而不是类,
+ /// - 它们是可变的而不是只读的,并且
+ /// - 它们的成员(例如 Item1、Item2 等)是字段而不是属性.
+ ///
+ public struct ValueTuple
+ : IEquatable, IStructuralEquatable, IStructuralComparable, IComparable, IComparable, ITupleInternal
+ {
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if is a .
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple;
+ }
+
+ /// Returns a value indicating whether this instance is equal to a specified value.
+ /// An instance to compare to this instance.
+ /// true if has the same value as this instance; otherwise, false.
+ public bool Equals(ValueTuple other)
+ {
+ return true;
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ return other is ValueTuple;
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return 0;
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ return 0;
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return 0;
+ }
+
+ /// Returns the hash code for this instance.
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return 0;
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return 0;
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return 0;
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form ().
+ ///
+ public override string ToString()
+ {
+ return "()";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return ")";
+ }
+
+ int ITupleInternal.Size => 0;
+
+ /// Creates a new struct 0-tuple.
+ /// A 0-tuple.
+ public static ValueTuple Create() => new();
+
+ /// Creates a new struct 1-tuple, or singleton.
+ /// The type of the first component of the tuple.
+ /// The value of the first component of the tuple.
+ /// A 1-tuple (singleton) whose value is (item1).
+ public static ValueTuple Create(T1 item1) => new(item1);
+
+ /// Creates a new struct 2-tuple, or pair.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// A 2-tuple (pair) whose value is (item1, item2).
+ public static ValueTuple Create(T1 item1, T2 item2) => new(item1, item2);
+
+ /// Creates a new struct 3-tuple, or triple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// A 3-tuple (triple) whose value is (item1, item2, item3).
+ public static ValueTuple Create(T1 item1, T2 item2, T3 item3) =>
+ new(item1, item2, item3);
+
+ /// Creates a new struct 4-tuple, or quadruple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The type of the fourth component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// The value of the fourth component of the tuple.
+ /// A 4-tuple (quadruple) whose value is (item1, item2, item3, item4).
+ public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4) =>
+ new(item1, item2, item3, item4);
+
+ /// Creates a new struct 5-tuple, or quintuple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The type of the fourth component of the tuple.
+ /// The type of the fifth component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// The value of the fourth component of the tuple.
+ /// The value of the fifth component of the tuple.
+ /// A 5-tuple (quintuple) whose value is (item1, item2, item3, item4, item5).
+ public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) =>
+ new(item1, item2, item3, item4, item5);
+
+ /// Creates a new struct 6-tuple, or sextuple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The type of the fourth component of the tuple.
+ /// The type of the fifth component of the tuple.
+ /// The type of the sixth component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// The value of the fourth component of the tuple.
+ /// The value of the fifth component of the tuple.
+ /// The value of the sixth component of the tuple.
+ /// A 6-tuple (sextuple) whose value is (item1, item2, item3, item4, item5, item6).
+ public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) =>
+ new(item1, item2, item3, item4, item5, item6);
+
+ /// Creates a new struct 7-tuple, or septuple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The type of the fourth component of the tuple.
+ /// The type of the fifth component of the tuple.
+ /// The type of the sixth component of the tuple.
+ /// The type of the seventh component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// The value of the fourth component of the tuple.
+ /// The value of the fifth component of the tuple.
+ /// The value of the sixth component of the tuple.
+ /// The value of the seventh component of the tuple.
+ /// A 7-tuple (septuple) whose value is (item1, item2, item3, item4, item5, item6, item7).
+ public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) =>
+ new(item1, item2, item3, item4, item5, item6, item7);
+
+ /// Creates a new struct 8-tuple, or octuple.
+ /// The type of the first component of the tuple.
+ /// The type of the second component of the tuple.
+ /// The type of the third component of the tuple.
+ /// The type of the fourth component of the tuple.
+ /// The type of the fifth component of the tuple.
+ /// The type of the sixth component of the tuple.
+ /// The type of the seventh component of the tuple.
+ /// The type of the eighth component of the tuple.
+ /// The value of the first component of the tuple.
+ /// The value of the second component of the tuple.
+ /// The value of the third component of the tuple.
+ /// The value of the fourth component of the tuple.
+ /// The value of the fifth component of the tuple.
+ /// The value of the sixth component of the tuple.
+ /// The value of the seventh component of the tuple.
+ /// The value of the eighth component of the tuple.
+ /// An 8-tuple (octuple) whose value is (item1, item2, item3, item4, item5, item6, item7, item8).
+ public static ValueTuple> Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) =>
+ new(item1, item2, item3, item4, item5, item6, item7, ValueTuple.Create(item8));
+
+ internal static int CombineHashCodes(int h1, int h2)
+ {
+ return HashHelpers.Combine(HashHelpers.Combine(HashHelpers.RandomSeed, h1), h2);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2), h3);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3, int h4)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2, h3), h4);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4), h5);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5), h6);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5, h6), h7);
+ }
+
+ internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8)
+ {
+ return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5, h6, h7), h8);
+ }
+ }
+
+ /// Represents a 1-tuple, or singleton, as a value type.
+ /// The type of the tuple's only component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ public ValueTuple(T1 item1)
+ {
+ Item1 = item1;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its field
+ /// is equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ return Comparer.Default.Compare(Item1, objTuple.Item1);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ return Comparer.Default.Compare(Item1, other.Item1);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Compare(Item1, objTuple.Item1);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return EqualityComparer.Default.GetHashCode(Item1);
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return comparer.GetHashCode(Item1);
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return comparer.GetHashCode(Item1);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1),
+ /// where Item1 represents the value of . If the field is ,
+ /// it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 1;
+ }
+
+ ///
+ /// Represents a 2-tuple, or pair, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+
+ ///
+ /// The current instance's first component.
+ ///
+ public T2 Item2;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ public ValueTuple(T1 item1, T2 item2)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object based on a specified comparison method.
+ ///
+ /// The object to compare with this instance.
+ /// An object that defines the method to use to evaluate whether the two objects are equal.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ ///
+ /// This member is an explicit interface member implementation. It can be used only when the
+ /// instance is cast to an interface.
+ ///
+ /// The implementation is called only if other is not ,
+ /// and if it can be successfully cast (in C#) or converted (in Visual Basic) to a
+ /// whose components are of the same types as those of the current instance. The IStructuralEquatable.Equals(Object, IEqualityComparer) method
+ /// first passes the values of the objects to be compared to the
+ /// implementation. If this method call returns , the method is
+ /// called again and passed the values of the two instances.
+ ///
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other is null or not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item2, other.Item2);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item2, objTuple.Item2);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2),
+ /// where Item1 and Item2 represent the values of the
+ /// and fields. If either field value is ,
+ /// it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 2;
+ }
+
+ ///
+ /// Represents a 3-tuple, or triple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item3, other.Item3);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item3, objTuple.Item3);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2),
+ comparer.GetHashCode(Item3));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2, Item3).
+ /// If any field value is , it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 3;
+ }
+
+ ///
+ /// Represents a 4-tuple, or quadruple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ /// The type of the tuple's fourth component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+ ///
+ /// The current instance's fourth component.
+ ///
+ public T4 Item4;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ /// The value of the tuple's fourth component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ Item4 = item4;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3)
+ && EqualityComparer.Default.Equals(Item4, other.Item4);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3)
+ && comparer.Equals(Item4, objTuple.Item4);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item3, other.Item3);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item4, other.Item4);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item3, objTuple.Item3);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item4, objTuple.Item4);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2),
+ comparer.GetHashCode(Item3),
+ comparer.GetHashCode(Item4));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2, Item3, Item4).
+ /// If any field value is , it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 4;
+ }
+
+ ///
+ /// Represents a 5-tuple, or quintuple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ /// The type of the tuple's fourth component.
+ /// The type of the tuple's fifth component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+ ///
+ /// The current instance's fourth component.
+ ///
+ public T4 Item4;
+ ///
+ /// The current instance's fifth component.
+ ///
+ public T5 Item5;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ /// The value of the tuple's fourth component.
+ /// The value of the tuple's fifth component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ Item4 = item4;
+ Item5 = item5;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3)
+ && EqualityComparer.Default.Equals(Item4, other.Item4)
+ && EqualityComparer.Default.Equals(Item5, other.Item5);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3)
+ && comparer.Equals(Item4, objTuple.Item4)
+ && comparer.Equals(Item5, objTuple.Item5);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item3, other.Item3);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item4, other.Item4);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item5, other.Item5);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item3, objTuple.Item3);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item4, objTuple.Item4);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item5, objTuple.Item5);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2),
+ comparer.GetHashCode(Item3),
+ comparer.GetHashCode(Item4),
+ comparer.GetHashCode(Item5));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5).
+ /// If any field value is , it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 5;
+ }
+
+ ///
+ /// Represents a 6-tuple, or sixtuple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ /// The type of the tuple's fourth component.
+ /// The type of the tuple's fifth component.
+ /// The type of the tuple's sixth component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+ ///
+ /// The current instance's fourth component.
+ ///
+ public T4 Item4;
+ ///
+ /// The current instance's fifth component.
+ ///
+ public T5 Item5;
+ ///
+ /// The current instance's sixth component.
+ ///
+ public T6 Item6;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ /// The value of the tuple's fourth component.
+ /// The value of the tuple's fifth component.
+ /// The value of the tuple's sixth component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ Item4 = item4;
+ Item5 = item5;
+ Item6 = item6;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3)
+ && EqualityComparer.Default.Equals(Item4, other.Item4)
+ && EqualityComparer.Default.Equals(Item5, other.Item5)
+ && EqualityComparer.Default.Equals(Item6, other.Item6);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3)
+ && comparer.Equals(Item4, objTuple.Item4)
+ && comparer.Equals(Item5, objTuple.Item5)
+ && comparer.Equals(Item6, objTuple.Item6);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item3, other.Item3);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item4, other.Item4);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item5, other.Item5);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item6, other.Item6);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item3, objTuple.Item3);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item4, objTuple.Item4);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item5, objTuple.Item5);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item6, objTuple.Item6);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2),
+ comparer.GetHashCode(Item3),
+ comparer.GetHashCode(Item4),
+ comparer.GetHashCode(Item5),
+ comparer.GetHashCode(Item6));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5, Item6).
+ /// If any field value is , it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 6;
+ }
+
+ ///
+ /// Represents a 7-tuple, or sentuple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ /// The type of the tuple's fourth component.
+ /// The type of the tuple's fifth component.
+ /// The type of the tuple's sixth component.
+ /// The type of the tuple's seventh component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+ ///
+ /// The current instance's fourth component.
+ ///
+ public T4 Item4;
+ ///
+ /// The current instance's fifth component.
+ ///
+ public T5 Item5;
+ ///
+ /// The current instance's sixth component.
+ ///
+ public T6 Item6;
+ ///
+ /// The current instance's seventh component.
+ ///
+ public T7 Item7;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ /// The value of the tuple's fourth component.
+ /// The value of the tuple's fifth component.
+ /// The value of the tuple's sixth component.
+ /// The value of the tuple's seventh component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
+ {
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ Item4 = item4;
+ Item5 = item5;
+ Item6 = item6;
+ Item7 = item7;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3)
+ && EqualityComparer.Default.Equals(Item4, other.Item4)
+ && EqualityComparer.Default.Equals(Item5, other.Item5)
+ && EqualityComparer.Default.Equals(Item6, other.Item6)
+ && EqualityComparer.Default.Equals(Item7, other.Item7);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3)
+ && comparer.Equals(Item4, objTuple.Item4)
+ && comparer.Equals(Item5, objTuple.Item5)
+ && comparer.Equals(Item6, objTuple.Item6)
+ && comparer.Equals(Item7, objTuple.Item7);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item3, other.Item3);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item4, other.Item4);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item5, other.Item5);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item6, other.Item6);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Item7, other.Item7);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item3, objTuple.Item3);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item4, objTuple.Item4);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item5, objTuple.Item5);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item6, objTuple.Item6);
+ if (c != 0) return c;
+
+ return comparer.Compare(Item7, objTuple.Item7);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7));
+ }
+
+ int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ private int GetHashCodeCore(IEqualityComparer comparer)
+ {
+ return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1),
+ comparer.GetHashCode(Item2),
+ comparer.GetHashCode(Item3),
+ comparer.GetHashCode(Item4),
+ comparer.GetHashCode(Item5),
+ comparer.GetHashCode(Item6),
+ comparer.GetHashCode(Item7));
+ }
+
+ int ITupleInternal.GetHashCode(IEqualityComparer comparer)
+ {
+ return GetHashCodeCore(comparer);
+ }
+
+ ///
+ /// Returns a string that represents the value of this instance.
+ ///
+ /// The string representation of this instance.
+ ///
+ /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5, Item6, Item7).
+ /// If any field value is , it is represented as .
+ ///
+ public override string ToString()
+ {
+ return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")";
+ }
+
+ string ITupleInternal.ToStringEnd()
+ {
+ return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")";
+ }
+
+ int ITupleInternal.Size => 7;
+ }
+
+ ///
+ /// Represents an 8-tuple, or octuple, as a value type.
+ ///
+ /// The type of the tuple's first component.
+ /// The type of the tuple's second component.
+ /// The type of the tuple's third component.
+ /// The type of the tuple's fourth component.
+ /// The type of the tuple's fifth component.
+ /// The type of the tuple's sixth component.
+ /// The type of the tuple's seventh component.
+ /// The type of the tuple's eighth component.
+ public struct ValueTuple
+ : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal
+ where TRest : struct
+ {
+ ///
+ /// The current instance's first component.
+ ///
+ public T1 Item1;
+ ///
+ /// The current instance's second component.
+ ///
+ public T2 Item2;
+ ///
+ /// The current instance's third component.
+ ///
+ public T3 Item3;
+ ///
+ /// The current instance's fourth component.
+ ///
+ public T4 Item4;
+ ///
+ /// The current instance's fifth component.
+ ///
+ public T5 Item5;
+ ///
+ /// The current instance's sixth component.
+ ///
+ public T6 Item6;
+ ///
+ /// The current instance's seventh component.
+ ///
+ public T7 Item7;
+ ///
+ /// The current instance's eighth component.
+ ///
+ public TRest Rest;
+
+ ///
+ /// Initializes a new instance of the value type.
+ ///
+ /// The value of the tuple's first component.
+ /// The value of the tuple's second component.
+ /// The value of the tuple's third component.
+ /// The value of the tuple's fourth component.
+ /// The value of the tuple's fifth component.
+ /// The value of the tuple's sixth component.
+ /// The value of the tuple's seventh component.
+ /// The value of the tuple's eight component.
+ public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest)
+ {
+ if (rest is not ITupleInternal)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleLastArgumentNotAValueTuple);
+ }
+
+ Item1 = item1;
+ Item2 = item2;
+ Item3 = item3;
+ Item4 = item4;
+ Item5 = item5;
+ Item6 = item6;
+ Item7 = item7;
+ Rest = rest;
+ }
+
+ ///
+ /// Returns a value that indicates whether the current instance is equal to a specified object.
+ ///
+ /// The object to compare with this instance.
+ /// if the current instance is equal to the specified object; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance under the following conditions:
+ ///
+ /// - It is a value type.
+ /// - Its components are of the same types as those of the current instance.
+ /// - Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component.
+ ///
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ValueTuple tuple && Equals(tuple);
+ }
+
+ ///
+ /// Returns a value that indicates whether the current
+ /// instance is equal to a specified .
+ ///
+ /// The tuple to compare with this instance.
+ /// if the current instance is equal to the specified tuple; otherwise, .
+ ///
+ /// The parameter is considered to be equal to the current instance if each of its fields
+ /// are equal to that of the current instance, using the default comparer for that field's type.
+ ///
+ public bool Equals(ValueTuple other)
+ {
+ return EqualityComparer.Default.Equals(Item1, other.Item1)
+ && EqualityComparer.Default.Equals(Item2, other.Item2)
+ && EqualityComparer.Default.Equals(Item3, other.Item3)
+ && EqualityComparer.Default.Equals(Item4, other.Item4)
+ && EqualityComparer.Default.Equals(Item5, other.Item5)
+ && EqualityComparer.Default.Equals(Item6, other.Item6)
+ && EqualityComparer.Default.Equals(Item7, other.Item7)
+ && EqualityComparer.Default.Equals(Rest, other.Rest);
+ }
+
+ bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer)
+ {
+ if (other == null || other is not ValueTuple) return false;
+
+ var objTuple = (ValueTuple)other;
+
+ return comparer.Equals(Item1, objTuple.Item1)
+ && comparer.Equals(Item2, objTuple.Item2)
+ && comparer.Equals(Item3, objTuple.Item3)
+ && comparer.Equals(Item4, objTuple.Item4)
+ && comparer.Equals(Item5, objTuple.Item5)
+ && comparer.Equals(Item6, objTuple.Item6)
+ && comparer.Equals(Item7, objTuple.Item7)
+ && comparer.Equals(Rest, objTuple.Rest);
+ }
+
+ int IComparable.CompareTo(object other)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ return CompareTo((ValueTuple)other);
+ }
+
+ /// Compares this instance to a specified instance and returns an indication of their relative values.
+ /// An instance to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and .
+ /// Returns less than zero if this instance is less than , zero if this
+ /// instance is equal to , and greater than zero if this instance is greater
+ /// than .
+ ///
+ public int CompareTo(ValueTuple other)
+ {
+ int c = Comparer.Default.Compare(Item1, other.Item1);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item2, other.Item2);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item3, other.Item3);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item4, other.Item4);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item5, other.Item5);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item6, other.Item6);
+ if (c != 0) return c;
+
+ c = Comparer.Default.Compare(Item7, other.Item7);
+ if (c != 0) return c;
+
+ return Comparer.Default.Compare(Rest, other.Rest);
+ }
+
+ int IStructuralComparable.CompareTo(object? other, IComparer comparer)
+ {
+ if (other == null) return 1;
+
+ if (other is not ValueTuple)
+ {
+ throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other));
+ }
+
+ var objTuple = (ValueTuple)other;
+
+ int c = comparer.Compare(Item1, objTuple.Item1);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item2, objTuple.Item2);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item3, objTuple.Item3);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item4, objTuple.Item4);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item5, objTuple.Item5);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item6, objTuple.Item6);
+ if (c != 0) return c;
+
+ c = comparer.Compare(Item7, objTuple.Item7);
+ if (c != 0) return c;
+
+ return comparer.Compare(Rest, objTuple.Rest);
+ }
+
+ ///
+ /// Returns the hash code for the current instance.
+ ///
+ /// A 32-bit signed integer hash code.
+ public override int GetHashCode()
+ {
+ // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple
+ if (Rest is not ITupleInternal rest)
+ {
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7));
+ }
+
+ int size = rest.Size;
+ if (size >= 8) { return rest.GetHashCode(); }
+
+ // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest
+ int k = 8 - size;
+ switch (k)
+ {
+ case 1:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 2:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 3:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 4:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 5:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 6:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer.Default.GetHashCode(Item6),
+ EqualityComparer.Default.GetHashCode(Item7),
+ rest.GetHashCode());
+ case 7:
+ case 8:
+ return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1),
+ EqualityComparer.Default.GetHashCode(Item2),
+ EqualityComparer