diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..f76aad0b8e204ddad3a675375bd5be6cc73eed8b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,225 @@
+# 如果要从更高级别的目录继承 .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_foreach_explicit_cast_in_source = when_strongly_typed
+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 = 0
+
+# 新行首选项
+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_extended_property_pattern = 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_style_namespace_declarations = block_scoped
+csharp_style_prefer_method_group_conversion = true
+csharp_style_prefer_top_level_statements = 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_prefer_index_operator = true
+csharp_style_prefer_local_over_anonymous_function = true
+csharp_style_prefer_null_check_over_type_check = true
+csharp_style_prefer_range_operator = true
+csharp_style_prefer_tuple_swap = true
+csharp_style_prefer_utf8_string_literals = 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 = false
+csharp_indent_case_contents_when_block = false
+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..2a9f81779649cb8451f5461b613c5d3273dc28fc 100644
--- a/IFoxCAD.sln
+++ b/IFoxCAD.sln
@@ -1,15 +1,44 @@
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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{786E7347-B116-4F26-9AEF-33EB0AB88D58}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ .gitattributes = .gitattributes
+ .gitignore = .gitignore
+ LICENSE = LICENSE
+ README.md = README.md
+ EndProjectSection
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.Acad08", "src\IFoxCAD.Cad\IFoxCAD.Aacad08\IFoxCAD.Acad08.csproj", "{36F87D06-88B3-45E3-A2A8-0FC737B25428}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IFox.Cad.Library", "IFox.Cad.Library", "{465C4E39-FBA2-417A-AB31-BDC01601F420}"
+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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Acad09plus", "src\IFoxCAD.Cad\IFoxCAD.Aacad09plus\IFoxCAD.Acad09plus.csproj", "{CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestShared", "tests\TestShared\TestShared.shproj", "{CED63D2D-0AF6-4831-806D-5E8E9B0D0A07}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestAcad08", "tests\TestAcad08\TestAcad08.csproj", "{8C573180-523D-427D-8030-CAA7D6B5EB6B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestAcad09plus", "tests\TestAcad09plus\TestAcad09plus.csproj", "{5F478F68-19BC-4A3A-AF39-8728F8D396DD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{C0BEFC15-6DF7-4636-BC76-4A0B88231470}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.LoadEx", "src\IFoxCAD.LoadForm\IFoxCAD.LoadEx.csproj", "{BFA1C130-8D87-45D0-8E79-301C1841A7A1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Gcad", "src\IFoxCAD.Cad\IFoxCAD.Gcad\IFoxCAD.Gcad.csproj", "{D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.Zcad", "src\IFoxCAD.Cad\IFoxCAD.Zcad\IFoxCAD.Zcad.csproj", "{751D15FC-B664-4B71-BB99-529E22EE1C4F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -17,14 +46,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
- {B1602568-F023-46C7-B635-3CB281F1EC00}.Release|Any CPU.Build.0 = Release|Any CPU
{D820D629-1AB3-4BE3-A772-CB753D98CCB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D820D629-1AB3-4BE3-A772-CB753D98CCB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D820D629-1AB3-4BE3-A772-CB753D98CCB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -33,11 +54,64 @@ 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
+ {36F87D06-88B3-45E3-A2A8-0FC737B25428}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {36F87D06-88B3-45E3-A2A8-0FC737B25428}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {36F87D06-88B3-45E3-A2A8-0FC737B25428}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {36F87D06-88B3-45E3-A2A8-0FC737B25428}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8C573180-523D-427D-8030-CAA7D6B5EB6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8C573180-523D-427D-8030-CAA7D6B5EB6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8C573180-523D-427D-8030-CAA7D6B5EB6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8C573180-523D-427D-8030-CAA7D6B5EB6B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BFA1C130-8D87-45D0-8E79-301C1841A7A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BFA1C130-8D87-45D0-8E79-301C1841A7A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BFA1C130-8D87-45D0-8E79-301C1841A7A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BFA1C130-8D87-45D0-8E79-301C1841A7A1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57}.Release|Any CPU.Build.0 = Release|Any CPU
+ {751D15FC-B664-4B71-BB99-529E22EE1C4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {751D15FC-B664-4B71-BB99-529E22EE1C4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {751D15FC-B664-4B71-BB99-529E22EE1C4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {751D15FC-B664-4B71-BB99-529E22EE1C4F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {36F87D06-88B3-45E3-A2A8-0FC737B25428} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {82FB8450-B971-4E30-859F-4B2DDB81F590} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {CC46E4E2-90DF-48F5-B3D7-83FAFED58F2A} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {CED63D2D-0AF6-4831-806D-5E8E9B0D0A07} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {8C573180-523D-427D-8030-CAA7D6B5EB6B} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {D0CE63A9-2DBA-4263-9749-E8CD3EA0DB57} = {465C4E39-FBA2-417A-AB31-BDC01601F420}
+ {751D15FC-B664-4B71-BB99-529E22EE1C4F} = {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*{36f87d06-88b3-45e3-a2a8-0fc737b25428}*SharedItemsImports = 5
+ tests\TestShared\TestShared.projitems*{5f478f68-19bc-4a3a-af39-8728f8d396dd}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{751d15fc-b664-4b71-bb99-529e22ee1c4f}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{82fb8450-b971-4e30-859f-4b2ddb81f590}*SharedItemsImports = 13
+ tests\TestShared\TestShared.projitems*{8c573180-523d-427d-8030-caa7d6b5eb6b}*SharedItemsImports = 5
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{cc46e4e2-90df-48f5-b3d7-83fafed58f2a}*SharedItemsImports = 5
+ tests\TestShared\TestShared.projitems*{ced63d2d-0af6-4831-806d-5e8e9b0d0a07}*SharedItemsImports = 13
+ src\IFoxCAD.Cad.Shared\IFoxCAD.Cad.Shared.projitems*{d0ce63a9-2dba-4263-9749-e8cd3ea0db57}*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..5d9e254dba52d2b4b10c3efd0643fb43d7eeb1cc 100644
--- a/README.md
+++ b/README.md
@@ -1,54 +1,122 @@
# IFoxCAD
+#### 释义
+IFox中:
+- IF:为Inspire Function(中文名:跃动方程)的首字母缩写
+- Fox:起初 **雪山飞狐(又狐哥)** 在明经论坛发布了[开源库](http://bbs.mjtd.com/thread-75701-1-1.html),后来狐哥自己的项目进行了极大的丰富后形成NFox类库。
+
+ 在 **落魄山人(又小山山)** 开始学习c#开发后,由于这个人过于懒,不想自己写基础的函数了,所以厚颜无耻的跟狐哥要来了 **NFox** 的源码。
+
+ 在学习了一阵源码后,发现狐哥的代码惊天地,泣鬼神,惊为天人,直接跪服,从此成为狐哥的脑残粉。
+
+ 为不使明珠蒙尘,特向狐哥申请是否可以开源,经原作者狐哥同意,正式发布 **NFox** 开源类库。
+
+ 后来本人多次二逼操作后, **NFox** 莫名无法运行,找不到原因,以及原代码嵌套引用多,逻辑复杂,痛定思痛,遂放弃 **NFox** 的开发,基于 **NFox** 重构为 **IFox** ,重新发布开源项目,取名为`IF+Fox=IFox`,一语双关,简洁而不简单。当然这些都是掩饰,其实就是 **I(爱)Fox(狐哥)** 。
+
+ **Inspire Function(中文名:跃动方程)及 IFoxCad 的名字均为小轩轩起名**
+
#### 介绍
-基于.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拥有最新的分析器和语法.
-#### 使用说明
+#### 让 IFox 作为您的子模块
-1. 快速入门
+IFox的[jing分支](https://gitee.com/inspirefunction/ifoxcad/tree/jing/)是一个多cad版本分支,您可以利用此作为您的[git项目子模块](https://www.cnblogs.com/JJBox/p/13876501.html#_label13).
- - 打开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依赖的库。
- - 添加引用
+子模块是以`共享工程`的方式加入到您的工程的,其为`IFoxCAD.Cad.Shared`:
- ```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. 千万不要用`IFoxCAD.Cad`内的工程作为引用,否则您将遭遇cad加载失效.
- - 添加代码
+2. 一些全局命名空间的缺少,我们也建议您使用全局命名空间来补充,
+ 您只需要按照`IFoxCAD.Cad`的`GlobalUsings.cs`文件一样添加就好了.
+3. 若您使用acad08版本,需要在您的工程中设置`ac2008`和`ac2009`(大小写敏感)两个预定义标签.
+ 方能启用08工程中缺少的09工程才有的类.
+ 同时我们在`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);
- }
- ```
- 这段代码就是在cad的当前空间内添加了一条直线。
+#### IFoxCad 项目模版
+
+可以在vs扩展菜单-管理扩展中搜索ifoxcad,即可安装项目模板。使用项目模版可以方便的创建支持多目标多版本的使用ifoxcad类库的项目和类。如果无法在vs的市场里下载,就去上面的QQ群里下载。
+
+#### 安装教程
+
+1. 新建net standard 类库
+2. 修改项目`.csproj`的`TargetFrameworks`为net45,保存重加载项目,这里需要注意和cad版本对照.
+3. 右键项目,管理nuget程序包,搜索ifoxcad,安装最新版就可以了.
+
+#### 使用说明
+
+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
+
+
+ ```
+
+ - 右键项目文件,选择管理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(nameof(Hello))]
+ public void Hello()
+ {
+ using DBTrans tr = new();
+ 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,32 +128,111 @@
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 特性
+ }
+
+ }
+
+ // 其他的类中的函数:
+ // 实现自动接口之后,在任意一个函数上面使用此特性,减少每次改动 CmdINI 类
+ public class AutoTest
+ {
+ [IFoxInitialize]
+ public void Initialize()
+ {
+ // TODO 您想在加载dll之后自动执行的函数
+ }
+ [IFoxInitialize]
+ public void InitTwo()
+ {
+ // TODO 您想在加载dll之后自动执行的函数
+ // 可以随便在哪里类里 可以多次实现 IFoxInitialize 特性
}
- public override void Terminate() //实现接口函数
+ [IFoxInitialize(isInitialize: false)] // 特性的参数为false的时候就表示卸载时执行的函数
+ public void Terminate()
{
- throw new NotImplementedException();
+ // TODO 您想在关闭cad时自动执行的函数
}
}
```
-
+
+
+
7. 天秀的打开模式提权
由于cad的对象是有打开模式,是否可写等等,为了安全起见,在处理对象时,一般是用读模式打开,然后需要写数据的时候在提权为写模式,然后在降级到读模式,但是这个过程中,很容易漏掉某些步骤,然后cad崩溃。为了处理这些情况,内裤提供了提权类来保证读写模式的有序转换。
```c#
- using(line.ForWrite()) //开启对象写模式提权事务
+ using(line.ForWrite()) // 开启对象写模式提权事务
{
- //处理代码
- } //关闭事务自动处理读写模式
+ // 处理代码
+ } // 关闭事务自动处理读写模式
```
-8. 未完待续。。。。
\ No newline at end of file
+8. 未完待续。。。。
+
+
+
+
+
+#### 屏蔽IFox.Basal的元组功能
+
+由于c#在每个版本提供的元组功能不一样(有的中间版本缺少),所以IFox内置了元组功能,但是内置元组又会引起某些用户的工程冲突.
+
+因此您需要制作一个影子工程:
+
+1. 您需要具备使用git子模块的能力,引用jing分支中的源码.
+
+ 子模块是为了保证您不修改IFox项目,因为你需要定期`git pull`更新组织提供的内容.
+
+ 熟悉子模块之后,你需要把IFox项目一个个加入你的解决方案,
+
+ 除了本次主角IFox.Basal.
+
+2. 在子模块文件夹外新建 IFox.Basal(影) 文件夹
+
+3. 复制 IFox.Basal(本) 的 .csproj 到上一步的文件夹.
+
+4. 修改 .csproj(影) 利用引用链接的方式进行引用 IFox.Basal(本) 的文件,不引用CLS就等于屏蔽了元组
+
+ ```xml
+
+
+
+
+ ```
+
+5. 修改 .csproj(影) 引入微软提供的元组 nuget: `System.ValueTuple` (或者你喜欢的)
+
+6. 解决方案加入 .csproj(影) 之后被内部其他项目引用.
+
+这个方法便可以把 影子工程 独立在IFox项目外,令`git pull`仍然有效,
+
+并且 本体工程 不做大更改的时候,影子工程更新幅度非常少,也多亏csproj改版了,不然也没有这个骚操作.
+
diff --git "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png" "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png"
new file mode 100644
index 0000000000000000000000000000000000000000..459930b8d54d075d94b4d06e960fbbc7edbdd17b
Binary files /dev/null and "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png" differ
diff --git "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md" "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md"
new file mode 100644
index 0000000000000000000000000000000000000000..e00e39603b72b6fb6f2ddddc36a9b0a160d59577
--- /dev/null
+++ "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md"
@@ -0,0 +1,143 @@
+# IFox工程规范
+
+## 代码规范
+
+### 0x01 分离逻辑代码和业务代码
+
+Good:
+
+```c#
+foreach (xx in yyy)
+ if (xx == "a")
+ {
+ 业务();
+ break;
+ }
+```
+
+Bad:
+
+```c#
+bool flag = false;
+foreach (xx in yyy)
+ if (xx == "a")
+ {
+ 业务();
+ flag = true;
+ break;
+ }
+if(!flag)
+ 其他业务();
+```
+Good:
+
+```c#
+bool flag = false;
+foreach (xx in yyy)
+ if (xx == "a")
+ {
+ flag = true;
+ break;
+ }
+if(!flag)
+ 其他业务();
+else
+ 业务();
+```
+
+主要原因是统一业务在判断分支上,能够更清晰分离逻辑代码和业务代码.
+
+
+### 0x02 分离逻辑代码和业务代码
+
+
+
+上述代码中出现了这种情形: for {业务1,业务2,业务1,业务2....}
+
+如果有这样的逻辑,那么我们看代码的时候总是认为业务2某种条件必须要跟着业务1.
+
+优化代码的人一看:这代码就不能动了!! 相信我,若干年后的你就是这个优化代码的人.
+
+所以这样的情况下,我们采用的是用个`List`收集拆离(业务)的id,然后在最后进行循环拆离(业务).
+
+### 0x03 .editorconfig 配置要求
+
+c#的代码风格是两个大括号隔行
+
+```c#
+if()
+{
+ ...
+}
+```
+
+但是,由于vs没有制作好的原因,导致`委托箭头`代码格式化总是会出现格式化错误.
+所以我们推荐用 .editorconfig 文件约束这个`委托箭头`
+
+在.edirorconfig文件上面增加此句:
+
+```
+csharp_style_var_elsewhere = false
+```
+
+没有这个文件的话,请使用如下步骤:
+
+```mermaid
+graph LR
+vs --> 选项 --> 文本编辑器 --> c# -->代码样式,展开它 --> 格式设置 --> 新行 --> 右页,大括号的新行选项 --> 将lambda表达式的左括号置于新行,取消掉勾勾
+```
+
+保存为 .editorconfig 文件,并放在.sln旁边,加入git管理:
+
+```mermaid
+graph LR
+vs --> 选项 --> 文本编辑器 --> c# -->代码样式 --> 右页,基于设置生成.editorconfig文件 --> 保存到工程中
+```
+
+以后每次打开工程vs会自动识别这个 .editorconfig 文件,而不会用你电脑默认设置的.
+
+
+
+### 0x04 所有的注释符号//后面加空格
+
+利用此正则替换:
+
+```
+(?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();
+ }
+}
\ No newline at end of file
diff --git a/src/IFoxCAD.Basal/CLS/Range.cs b/src/IFoxCAD.Basal/CLS/Range.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43dce547422fcb85141111359c24431ebc22e3ac
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/Range.cs
@@ -0,0 +1,102 @@
+// 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);
+ }
+}
\ No newline at end of file
diff --git a/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs b/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0cfa9c9416cd6ab11677c50f32e8fbb97684527
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/RuntimeHelpers.cs
@@ -0,0 +1,45 @@
+#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;
+
+// 编译提示多个程序集中定义,屏蔽不了,但是不影响编译
+// #pragma warning disable CS1685 // 类型与导入类型冲突
+public static class RuntimeHelpers
+// #pragma warning restore CS1685 // 类型与导入类型冲突
+{
+ ///
+ /// 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()) // 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..93e61930c31b8277948fa060629cb1d813a04ba1
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/TupleElementNamesAttribute.cs
@@ -0,0 +1,48 @@
+// 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;
+
+///
+/// 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)
+ {
+ _transformNames = transformNames ?? throw new ArgumentNullException(nameof(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..568ddb9fdeb63d3ee7308b3dc0f33823234ea77d
--- /dev/null
+++ b/src/IFoxCAD.Basal/CLS/ValueTuple.cs
@@ -0,0 +1,2140 @@
+// 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.Default.GetHashCode(Item3),
+ EqualityComparer.Default.GetHashCode(Item4),
+ EqualityComparer.Default.GetHashCode(Item5),
+ EqualityComparer