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 f87938bc17c2093cf788a972cac0d220f9964d8d..e910608fc1ecabe29cb4e88eeab0a35a2b752e7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -398,4 +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..802ff1cc56ccadea875f242dea64a2a32a0c0d69 100644
--- a/IFoxCAD.sln
+++ b/IFoxCAD.sln
@@ -1,15 +1,65 @@
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}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{786E7347-B116-4F26-9AEF-33EB0AB88D58}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ .gitattributes = .gitattributes
+ .gitignore = .gitignore
+ EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DBTrans.test", "tests\DBTrans.test\DBTrans.test.csproj", "{B1602568-F023-46C7-B635-3CB281F1EC00}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestConsole", "tests\TestConsole\TestConsole.csproj", "{E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.WPF", "src\IFoxCAD.WPF\IFoxCAD.WPF.csproj", "{D820D629-1AB3-4BE3-A772-CB753D98CCB8}"
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestShared", "tests\TestShared\TestShared.shproj", "{CED63D2D-0AF6-4831-806D-5E8E9B0D0A07}"
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}") = "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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Basal", "Basal", "{1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A}"
+ ProjectSection(SolutionItems) = preProject
+ src\Basal\Directory.Build.props = src\Basal\Directory.Build.props
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.Basal", "src\Basal\IFox.Basal\IFox.Basal.csproj", "{FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "IFox.Basal.Shared", "src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.shproj", "{C823514A-2BC2-45C2-ACED-18924A7B80BF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.Basal.Source", "src\Basal\IFox.Basal.Source\IFox.Basal.Source.csproj", "{D0C6824C-53A3-4C16-AE7B-3227F18C5039}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "IFox.CAD.Shared", "src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.shproj", "{20F254F7-AEE5-42AE-A9B3-149BBDC7397F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CAD", "CAD", "{B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}"
+ ProjectSection(SolutionItems) = preProject
+ src\CAD\Directory.Build.props = src\CAD\Directory.Build.props
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.Source", "src\CAD\IFox.CAD.Source\IFox.CAD.Source.csproj", "{88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.ACAD", "src\CAD\IFox.CAD.ACAD\IFox.CAD.ACAD.csproj", "{EF20E632-70A9-40EB-8C9A-539FD85FAFAD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.GCAD", "src\CAD\IFox.CAD.GCAD\IFox.CAD.GCAD.csproj", "{F388F4B9-F636-414A-9BC9-2B008517B441}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.ZCAD", "src\CAD\IFox.CAD.ZCAD\IFox.CAD.ZCAD.csproj", "{3D7D095D-EF0A-40B3-9776-5F08C61FD614}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WPF", "WPF", "{1EE1F817-39D3-43E5-B087-E7AD4D0BEC93}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.WPF", "src\WPF\IFox.WPF.csproj", "{6ED0A677-6621-4493-AF58-71C2BF31DFCE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{DA8EA8E7-A98E-4565-A3BF-97855988DB8E}"
+ ProjectSection(SolutionItems) = preProject
+ docs\0x01代码规范.md = docs\0x01代码规范.md
+ docs\DBTrans.md = docs\DBTrans.md
+ LICENSE = LICENSE
+ README.md = README.md
+ docs\SelectionFilter.md = docs\SelectionFilter.md
+ docs\SymbolTable.md = docs\SymbolTable.md
+ docs\WPF.md = docs\WPF.md
+ docs\关于IFoxCAD的架构说明.md = docs\关于IFoxCAD的架构说明.md
+ docs\关于扩展函数的说明.md = docs\关于扩展函数的说明.md
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -17,27 +67,71 @@ 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
- {D820D629-1AB3-4BE3-A772-CB753D98CCB8}.Release|Any CPU.Build.0 = Release|Any CPU
- {40BF07C4-100A-4810-A27B-4587CFB38E6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {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
+ {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
+ {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Release|Any CPU.Build.0 = Release|Any CPU
+ {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F388F4B9-F636-414A-9BC9-2B008517B441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F388F4B9-F636-414A-9BC9-2B008517B441}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F388F4B9-F636-414A-9BC9-2B008517B441}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F388F4B9-F636-414A-9BC9-2B008517B441}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.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}
+ {CED63D2D-0AF6-4831-806D-5E8E9B0D0A07} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {5F478F68-19BC-4A3A-AF39-8728F8D396DD} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470}
+ {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A}
+ {C823514A-2BC2-45C2-ACED-18924A7B80BF} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A}
+ {D0C6824C-53A3-4C16-AE7B-3227F18C5039} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A}
+ {20F254F7-AEE5-42AE-A9B3-149BBDC7397F} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}
+ {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}
+ {EF20E632-70A9-40EB-8C9A-539FD85FAFAD} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}
+ {F388F4B9-F636-414A-9BC9-2B008517B441} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}
+ {3D7D095D-EF0A-40B3-9776-5F08C61FD614} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}
+ {6ED0A677-6621-4493-AF58-71C2BF31DFCE} = {1EE1F817-39D3-43E5-B087-E7AD4D0BEC93}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31D6C754-CF6B-4AB0-9861-6923DD312350}
EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{20f254f7-aee5-42ae-a9b3-149bbdc7397f}*SharedItemsImports = 13
+ src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{3d7d095d-ef0a-40b3-9776-5f08c61fd614}*SharedItemsImports = 5
+ tests\TestShared\TestShared.projitems*{5f478f68-19bc-4a3a-af39-8728f8d396dd}*SharedItemsImports = 5
+ src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.projitems*{c823514a-2bc2-45c2-aced-18924a7b80bf}*SharedItemsImports = 13
+ tests\TestShared\TestShared.projitems*{ced63d2d-0af6-4831-806d-5e8e9b0d0a07}*SharedItemsImports = 13
+ src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{ef20e632-70a9-40eb-8c9a-539fd85fafad}*SharedItemsImports = 5
+ src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{f388f4b9-f636-414a-9bc9-2b008517b441}*SharedItemsImports = 5
+ src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.projitems*{ff4e1cde-eeb3-4be8-8c1d-6b5b17a299c7}*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..c29b07b76f66a8749a9effdd513d4cdc71b69bc3 100644
--- a/README.md
+++ b/README.md
@@ -1,91 +1,176 @@
-# IFoxCAD
+# IFoxCAD 说明
-#### 介绍
+基于.NET的Cad二次开发类库。
-基于.NET的Cad二次开发类库
+#### 一、项目来源
-#### 软件架构及相关说明
+起初 **雪山飞狐(又狐哥)** 在明经论坛发布了[开源库](http://bbs.mjtd.com/thread-75701-1-1.html),后来狐哥自己的项目进行了极大的丰富后形成NFox类库。然后 **落魄山人** 在征得 雪山飞狐的同意后,对NFox类库进行了整理,增加了注释等,重新发布了NFox类库。
-- [软件架构说明](/docs/关于IFoxCAD的架构说明.md)
+后来,经过一段时间的更新后,由于莫名其妙的原因NFox类库挂掉了。而这时山人同学已经基本吃透NFox类库,考虑到NFox的封装过于复杂,遂进行了重构。
-- [扩展函数说明](/docs/关于扩展函数的说明.md)
+重构的类库命名为IFoxCAD, 寓意为:**I(爱)Fox(狐哥)**,本项目发布于**Inspire Function(中文名:跃动方程)** 组织下,感谢 **小轩轩** 给起的名字。
-#### 安装教程
+可以加群交流:
-1. vs新建net standord 类库
-2. 修改项目TargetFramework为net45,保存重加载项目
-3. 右键项目,管理nuget程序包,搜索ifoxcad,安装最新版就可以了
+
-#### 使用说明
+#### 二、 快速入门
-1. 快速入门
+- 打开vs,新建一个standard类型的类库项目,**注意,需要选择类型的时候一定要选standard2.0**
- - 打开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依赖的库。
- - 添加引用
+- 双击项目,打开项目文件:
+
+ - 修改项目文件里的`netcore2.0`为`NET45`。其中的net45,可以改为NET45以上的标准TFM(如:net45、net46、net47等等)。同时可以指定多版本。具体的详细的教程见 [VS通过添加不同引用库,建立多条件编译](https://www.yuque.com/vicwjb/zqpcd0/ufbwyl)。
+
+ - 在 ` xxx ` 中增加 `preview`,主要是为了支持最新的语法,本项目采用了最新的语法编写。项目文件现在的内容类似如下:
- ```c#
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Runtime;
- using Autodesk.AutoCAD.Geometry;
- using Autodesk.AutoCAD.DatabaseServices;
- using IFoxCAD.Cad;
- ```
+```xml
+
+
+ net45
+ preview
+
+
+```
- - 添加代码
+- 右键项目文件,选择管理nuget程序包。
- ```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);
- }
- ```
+- 在nuget程序里搜索**ifox**,记得将包括预发行版打钩。截止本文最后更新时,nuget上最新的版本为ifox.cad.source 0.5.2.1版本和ifox.Basal.source 0.5.2.3版本。点击安装就可以。
- 这段代码就是在cad的当前空间内添加了一条直线。
+- 添加引用,在新建的项目里的cs文件里添加相关的引用
- - F6生成,然后打开cad,netload命令将刚刚生成的dll加载。
- - 运行hello命令,然后缩放一下视图,现在一条直线和一个圆已经显示在屏幕上了。
+```csharp
+using Autodesk.AutoCAD.ApplicationServices;
+using Autodesk.AutoCAD.EditorInput;
+using Autodesk.AutoCAD.Runtime;
+using Autodesk.AutoCAD.Geometry;
+using Autodesk.AutoCAD.DatabaseServices;
+using IFoxCAD.Cad;
+```
-2. [事务管理器用法](/docs/DBTrans.md)
+- 添加代码
-3. [选择集过滤器用法](/docs/SelectionFilter.md)
+```csharp
+[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);
+ // }
+}
+```
-4. [符号表用法](/docs/SymbolTable.md)
+这段代码就是在cad的当前空间内添加了一条直线。
-5. [WPF支持](/docs/WPF.md)
+- 生成,然后打开cad,netload命令将刚刚生成的dll加载。如果需要调试需要设置启动程序为cad。
-6. 天秀的自动加载与初始化
+- 运行hello命令,然后缩放一下视图,现在一条直线和一个圆已经显示在屏幕上了
- 为了将程序集的初始化和通过写注册表的方式实现自动加载统一设置,减少每次重复的工作量,内裤提供了`AutoRegAssem`抽象类来完成此功能,只要在需要初始化的类继承`AutoRegAssem`类,然后实现`Initialize()` 和`Terminate()`两个函数就可以了。特别强调的是,一个程序集里只能有一个类继承,不管是不是同一个命名空间。
+#### 三、屏蔽IFox的元组、索引、范围功能
- ```c#
- public class Test : AutoRegAssem //继承
- {
- public override void Initialize() //实现接口函数
- {
- throw new NotImplementedException();
- }
- public override void Terminate() //实现接口函数
- {
- throw new NotImplementedException();
- }
- }
- ```
+特别提醒: 考虑到早期的框架没有提供System.Range类型(net core 开始提供)、System.Index类型(net core 开始提供)、System.ValueTuple类型(net 47开始提供),本项目IFox.Basal包里包含了他们。 如果引用了包含System.Range等类型的第三方包(如IndexRange等),请在项目文件中定义NOINDEX、NORANGE、NOVALUETUPLE常量,以避免重复定义。上述代码能起作用的前提是用源码包,普通包暂时无解。
-7. 天秀的打开模式提权
+```xml
+
+ $(Configuration);NOINDEX;NORANGE;NOVALUETUPLE
+
+```
- 由于cad的对象是有打开模式,是否可写等等,为了安全起见,在处理对象时,一般是用读模式打开,然后需要写数据的时候在提权为写模式,然后在降级到读模式,但是这个过程中,很容易漏掉某些步骤,然后cad崩溃。为了处理这些情况,内裤提供了提权类来保证读写模式的有序转换。
+**NOINDEX、NORANGE、NOVALUETUPLE 分别针对三种类型,哪种类型冲突就定义哪种。**
+
+#### 四、编译 IFox 源码工程
+
+由于vs2022抛弃了某几个net版本,所以我们同时安装vs2019和vs2022,然后使用vs2022;
+其中的原因是vs2019拥有全部net版本,而vs2022拥有最新的分析器和语法。
+
+编译本项目需要你准备好git,具体的安装教程可以去网上搜索一下。当然也可以利用vs的git来完成。
+
+首先在gitee上fork本项目到你的账号,然后clone到本地。
+
+原生git使用命令行,打开终端/powershell/cmd,cd到你要存放的目录,然后运行下面的命令,把里面的yourname替换为你的名字,这样就在本地创建了一个ifoxcad文件夹,里面就是本项目的所有源码。
+
+```
+git clone https://gitee.com/yourname/ifoxcad.git
+```
+
+当然也可以采用vs的图形化操作,打开vs,选择 克隆存储库-->填入仓库地址和存放路径-->点击克隆。新手小白推荐用此办法。
+
+打开ifoxcad文件夹,双击解决方案文件,打开vs,等待项目打开,加载nuget包,然后生成就可以了。
+
+**切记,不要用低版本的vs打开本项目,因为本项目采用了某些新的语法,所以老版本的vs是不兼容的。**
+
+#### 五、IFoxCad 项目模版
+
+可以在vs扩展菜单-管理扩展中搜索ifoxcad,即可安装项目模板。使用项目模版可以方便的创建支持多目标多版本的使用ifoxcad类库的项目和类。如果无法在vs的市场里下载,就去上面的QQ群里下载。
+
+项目模版里的自动加载选择了简单api,ifox还提供了一套功能更强大的api,具体的可以参考[自动加载和初始化](/docs/autoreg.md)。
+
+#### 六、使用IFoxCad的几种方式
- ```c#
- using(line.ForWrite()) //开启对象写模式提权事务
+目前ifox提供了三种使用方式,**建议一般的用户使用第二种源码包的形式。有志于本项目发展并想提交点代码的可以选择第三种。**
+
+- 第一种是直接使用普通的nuget包。
+
+ 此种方式使用便捷,只要在项目中引用了IFox.CAD.ACAD的包,就可以直接使用了。缺点一是无法控制ifox提供的元组功能的屏蔽,导致和其他的三方包的冲突;二是生成目录里带有ifox的dll。
+
+- 第二种是使用源码包。
+
+ 此种方式使用便捷,只要在项目中引用了IFox.Basal.Source和IFox.CAD.Source两个nuget包就可以直接使用了。优点就是使用简单,生成的目录里没有ifox的dll,同时还可以通过定义预处理常量的方式屏蔽ifox提供的元组等功能。缺点就是无法修改源码,即便解包修改了,也不会同步到nuget上。
+
+- 第三种是使用git子模块。
+
+ 此种方法使用步骤复杂,需要熟悉git及其子模块的使用,需要引用ifox里的共享项目文件。优点就是可以使用最新的代码,可以修改代码。具体的可以参考如下说明进行:
+
+ **让 IFox 作为您的子模块**
+
+ IFox的develop分支是一个多cad版本分支,您可以利用此作为您的[git项目子模块](https://www.cnblogs.com/JJBox/p/13876501.html#_label13).
+
+ 子模块是以`共享工程`的方式加入到您的工程的,其为`IFox.CAD.Shared`:
+1. 千万不要用`IFox.CAD.ACAD`内的工程作为引用,否则您将遭遇cad加载失效.
+
+2. 一些全局命名空间的缺少,我们也建议您使用全局命名空间来补充,
+ 您只需要按照`IFox.CAD.ACAD`的`GlobalUsings.cs`文件一样添加就好了.
+
+3. 若您使用acad是09版本以下的,比如 07 08版本,建议你升级至09 版本以上.
+
+4. 上面的例子告诉了大家如何使用子模块。
+
+#### 七、软件架构及相关说明
+
+1. [软件架构说明](/docs/关于IFoxCAD的架构说明.md)
+
+2. [扩展函数说明](/docs/关于扩展函数的说明.md)
+
+3. [事务管理器用法](/docs/DBTrans.md)
+
+4. [选择集过滤器用法](/docs/SelectionFilter.md)
+
+5. [符号表用法](/docs/SymbolTable.md)
+
+6. [WPF支持](/docs/WPF.md)
+
+7. [自动加载与初始化](/docs/autoreg.md)
+
+8. 天秀的打开模式提权
+
+ 由于cad的对象是有打开模式,是否可写等等,为了安全起见,在处理对象时,一般是用读模式打开,然后需要写数据的时候在提权为写模式,然后在降级到读模式,但是这个过程中,很容易漏掉某些步骤,然后cad崩溃。为了处理这些情况,内裤提供了提权类来保证读写模式的有序转换。
+
+ ```csharp
+ // 第一种方式,采用的是事务管理的模式
+ using(line.ForWrite()) // 开启对象写模式提权事务
{
- //处理代码
- } //关闭事务自动处理读写模式
+ // 处理代码
+ } // 关闭事务自动处理读写模式
+ // 第二种方式,采用的是委托的形式
+ line.ForWrite(e => {
+ // 处理代码
+ });
```
-8. 未完待续。。。。
\ No newline at end of file
+9. 未完待续。。。。
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..26f09091f8e0321b4418e199aaa47792282ff1b5
--- /dev/null
+++ "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md"
@@ -0,0 +1,132 @@
+# 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 所有的注释符号//后面加空格
+
+利用此正则替换:
+
+```
+(?
- {
- ltt.AsciiDescription = "虚线";
- ltt.PatternLength = 0.95; //线型的总长度
- ltt.NumDashes = 4; //组成线型的笔画数目
- ltt.SetDashLengthAt(0, 0.5); //0.5个单位的划线
- ltt.SetDashLengthAt(1, -0.25); //0.25个单位的空格
- ltt.SetDashLengthAt(2, 0); // 一个点
- ltt.SetDashLengthAt(3, -0.25); //0.25个单位的空格
- });
+ "hah",
+ ltt =>
+ {
+ ltt.AsciiDescription = "虚线";
+ ltt.PatternLength = 0.95; //线型的总长度
+ ltt.NumDashes = 4; //组成线型的笔画数目
+ ltt.SetDashLengthAt(0, 0.5); //0.5个单位的划线
+ ltt.SetDashLengthAt(1, -0.25); //0.25个单位的空格
+ ltt.SetDashLengthAt(2, 0); // 一个点
+ ltt.SetDashLengthAt(3, -0.25); //0.25个单位的空格
+ });
// 这段代码同时演示了 ifoxcad 类库关于符号表的public ObjectId Add(string name, Action action)这个函数的用法。
// 或者直接调用:
tr.LinetypeTable.Add("hah", "虚线",0.95,new double[]{0.5,-0.25,0,-0.25});
// 获取线型表
tr.LinetypeTable["hah"];
```
-
- **其他符号表的操作类同。如果类库没有提供的Add函数的重载,那么Action委托可以完成你想完成的所有事情。**
+
+ **其他符号表的操作类同。如果类库没有提供的Add函数的重载,那么Action委托可以完成你想完成的所有事情。**
## 基础属性操作
@@ -125,16 +125,15 @@ using (DBTrans tr = new DBTrans()) // 第一步,开启事务
## 字典操作(未完待续)
- 扩展字典
-
+
`SetXRecord` 保存扩展数据到字典
-
+
`GetXRecord ` 获取扩展数据
- 对象字典
-
+
`SetToDictionary` 保存数据到字典
-
+
`GetFromDictionary` 从字典获取数据
-
+
`GetSubDictionary` 获取子对象字典
-
diff --git a/docs/SelectionFilter.md b/docs/SelectionFilter.md
index 1e50098bf6fdba1cf6d0830d0ab68c73e6adf439..bc31b55c3c7d630bd238e99c76ba8e830b4210fe 100644
--- a/docs/SelectionFilter.md
+++ b/docs/SelectionFilter.md
@@ -9,8 +9,8 @@
默认的使用桌子api来创建选择集(带过滤器)分三步:
1. 创建一个TypedValue数组来定义过滤器条件
-
- ```c#
+
+ ```csharp
TypedValue[] acTypValAr = new TypedValue[1]; // 创建数组
acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "CIRCLE"), 0);
// 添加一个过滤条件,例如选择圆
@@ -24,15 +24,15 @@
```
2. 创建SelectionFilter对象
-
- ```c#
+
+ ```csharp
// 将过滤器条件赋值给 SelectionFilter 对象
SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
```
3. 创建选择集
-
- ```c#
+
+ ```csharp
// 请求用户在图形区域选择对象
PromptSelectionResult acSSPrompt;
acSSPrompt = acDocEd.GetSelection(acSelFtr);
@@ -42,147 +42,147 @@
比如:
- 1. 过滤半径大于等于5.0的圆
-
- ```c#
- TypedValue[] acTypValAr = {
- new TypedValue((int)DxfCode.Start, "CIRCLE"),
- new TypedValue((int)DxfCode.Operator, ">="),
- new TypedValue(40, 5)
- };
- ```
-
- 2. 过滤单行文本或者多行文本
-
- ```c#
- TypedValue[] acTypValAr = {
- new TypedValue((int)DxfCode.Operator, "")
- };
- ```
-
- 3. 更复杂的过滤条件呢?比如选择的对象为不是位于0图层的直线,或者位于2图层的组码10的x坐标>10,y坐标>10的非圆图元。
-
- 对应的lisp代码如下:
-
- ```lisp
- '((-4 . "")
- (-4 . "not>")
- (-4 . "")
- (8 . "2")
- (-4 . ">,>,*")(10 10 10 0)
+1. 过滤半径大于等于5.0的圆
+
+ ```csharp
+ TypedValue[] acTypValAr = {
+ new TypedValue((int)DxfCode.Start, "CIRCLE"),
+ new TypedValue((int)DxfCode.Operator, ">="),
+ new TypedValue(40, 5)
+ };
+ ```
+
+2. 过滤单行文本或者多行文本
+
+ ```csharp
+ TypedValue[] acTypValAr = {
+ new TypedValue((int)DxfCode.Operator, "")
+ };
+ ```
+
+3. 更复杂的过滤条件呢?比如选择的对象为不是位于0图层的直线,或者位于2图层的组码10的x坐标>10,y坐标>10的非圆图元。
+
+ 对应的lisp代码如下:
+
+ ```lisp
+ '((-4 . "")
- (-4 . "or>"))
- ```
-
- 对应的c#代码:
-
- ```c#
- TypedValue[] acTypValAr = {
- new TypedValue((int)DxfCode.Operator, ""),
- new TypedValue((int)DxfCode.Operator, "not>"),
- new TypedValue((int)DxfCode.Operator, ""),
- new TypedValue((int)DxfCode.LayerName, "2"),
- new TypedValue((int)DxfCode.Operator, ">,>,*"),
- new TypedValue(10, new Point3d(10,10,0)),
- new TypedValue((int)DxfCode.Operator, "and>"),
- new TypedValue((int)DxfCode.Operator, "or>")
- };
- ```
-
- 这个过滤器是不是看起来很乱,一眼看去根本不知道是要过滤什么,写起来也很麻烦。所以说,虽然桌子提供了api,但是简单的过滤条件很好用,但是复杂的过滤条件就很复杂了。
-
- 因此NFox内裤提供了关于选择集过滤器的辅助类来帮助用户用更简单的方式来创建选择集的过滤器。
+ (-4 . "not>")
+ (-4 . "")
+ (8 . "2")
+ (-4 . ">,>,*")(10 10 10 0)
+ (-4 . "and>")
+ (-4 . "or>"))
+ ```
+
+ 对应的c#代码:
+
+ ```csharp
+ TypedValue[] acTypValAr = {
+ new TypedValue((int)DxfCode.Operator, ""),
+ new TypedValue((int)DxfCode.Operator, "not>"),
+ new TypedValue((int)DxfCode.Operator, ""),
+ new TypedValue((int)DxfCode.LayerName, "2"),
+ new TypedValue((int)DxfCode.Operator, ">,>,*"),
+ new TypedValue(10, new Point3d(10,10,0)),
+ new TypedValue((int)DxfCode.Operator, "and>"),
+ new TypedValue((int)DxfCode.Operator, "or>")
+ };
+ ```
+
+ 这个过滤器是不是看起来很乱,一眼看去根本不知道是要过滤什么,写起来也很麻烦。所以说,虽然桌子提供了api,但是简单的过滤条件很好用,但是复杂的过滤条件就很复杂了。
+
+ 因此IFox内裤提供了关于选择集过滤器的辅助类来帮助用户用更简单的方式来创建选择集的过滤器。
## 内裤过滤器对象与cad过滤器对应关系
IFoxCad内裤对于DxfCode.Operator枚举构建了一些辅助函数来表达关系运算和逻辑运算;提供了dxf函数来表达组码。其对应的关系如下表:
-| 内裤过滤器对象、函数 | cad .net api 过滤器对象、函数、枚举 | 备注 |
-| :------------------: | :---------------------------------: | :------------------------------: |
-| OpFilter | SelectionFilter | 隐式转换 |
-| OpOr | "" | |
-| Op.Or | "" | |
-| OpAnd | "" | |
-| Op.And | "" | |
-| OpNot | "" | |
-| OpXor | "" | |
-| OpEqual | 相等运算 | |
-| OpComp | 比较运算符 | |
-| Dxf() | 组码函数 | 仅用于过滤器中,不是组码操作函数 |
-| ! | "" | |
-| == | "=" | |
-| != | "!=" | |
-| > | ">" | |
-| < | "<" | |
-| >= | ">=" 或 ">,>,*" | ">,>,*"用于跟point3d比较 |
-| <= | "<=" 或 "<,<,*" | "<,<,*"用于跟point3d比较 |
-| & | "" | |
-| ^ | "" | |
-| \| | "" | |
+| 内裤过滤器对象、函数 | cad .net api 过滤器对象、函数、枚举 | 备注 |
+|:----------:|:------------------------:|:-------------------:|
+| OpFilter | SelectionFilter | 隐式转换 |
+| OpOr | "" | |
+| Op.Or | "" | |
+| OpAnd | "" | |
+| Op.And | "" | |
+| OpNot | "" | |
+| OpXor | "" | |
+| OpEqual | 相等运算 | |
+| OpComp | 比较运算符 | |
+| Dxf() | 组码函数 | 仅用于过滤器中,不是组码操作函数 |
+| ! | "" | |
+| == | "=" | |
+| != | "!=" | |
+| > | ">" | |
+| < | "<" | |
+| >= | ">=" 或 ">,>,*" | ">,>,*"用于跟point3d比较 |
+| <= | "<=" 或 "<,<,*" | "<,<,*"用于跟point3d比较 |
+| & | "" | |
+| ^ | "" | |
+| \| | "" | |
## 具体用法
IFoxCad内裤提供了三种方式来构建过滤器,其实大同小异,就是写法不一样,用户可以根据自己的喜好来选择。
- 第一种
-
- ```c#
+
+ ```csharp
var fd =
- new OpOr //定义一个 (-4 . "")
- {
- !new OpAnd //定义(-4 . "")(-4 . "not>")
- {
- { 0, "line" }, //{组码,组码值}
- { 8, "0" }, //{组码,组码值}
- },
- new OpAnd //定义(-4 . "")
- {
- !new OpEqual(0, "circle"), //定义(-4 . "")
- { 8, "2" }, //{组码,组码值}
- { 10, new Point3d(10,10,0), ">,>,*" } //(-4 . ">,>,*")(10 10 10 0)
- },
- };
+ new OpOr //定义一个 (-4 . "")
+ {
+ !new OpAnd //定义(-4 . "")(-4 . "not>")
+ {
+ { 0, "line" }, //{组码,组码值}
+ { 8, "0" }, //{组码,组码值}
+ },
+ new OpAnd //定义(-4 . "")
+ {
+ !new OpEqual(0, "circle"), //定义(-4 . "")
+ { 8, "2" }, //{组码,组码值}
+ { 10, new Point3d(10,10,0), ">,>,*" } //(-4 . ">,>,*")(10 10 10 0)
+ },
+ };
editor.SelectAll(fd); //这里直接传入fd就可以了
```
-
+
以上代码的含义为:选择的对象为不是位于0图层的直线,或者位于2图层的组码10的x坐标>10,y坐标>10的非圆图元。其同含义的lisp代码如下:
-
+
```lisp
'((-4 . "")
- (-4 . "not>")
- (-4 . "")
+ (-4 . "not>")
+ (-4 . "")
(8 . "2")
- (-4 . ">,>,*")(10 10 10 0)
+ (-4 . ">,>,*")(10 10 10 0)
(-4 . "and>")
(-4 . "or>"))
```
- 第二种
-
- ```c#
+
+ ```csharp
var p = new Point3d(10, 10, 0);
var f = OpFilter.Bulid(e =>
!(e.Dxf(0) == "line" & e.Dxf(8) == "0")
@@ -191,12 +191,12 @@ IFoxCad内裤提供了三种方式来构建过滤器,其实大同小异,就
& e.Dxf(10) >= p);
editor.SelectAll(f); //这里直接传入f就可以了
```
-
+
代码含义如第一种。
- 第三种
-
- ```c#
+
+ ```csharp
var f2 = OpFilter.Bulid(
e =>e.Or(
!e.And(e.Dxf(0) == "line", e.Dxf(8) == "0"),
@@ -204,5 +204,5 @@ IFoxCad内裤提供了三种方式来构建过滤器,其实大同小异,就
);
editor.SelectAll(f2); //这里直接传入f2就可以了
```
-
+
代码含义如第一种,第三种和第二种的写法非常像,区别就是关于 and 、or 、not 等运算符,一个是采用c#的语法,一个是采用定义的函数。and 与&等价,or与|等价,not 与!等价。
\ No newline at end of file
diff --git a/docs/SymbolTable.md b/docs/SymbolTable.md
index 0d450439eb0c17e953ee73163b268a5194f1a05e..a5144baea56a722688da09f929cfd04e9d243ed7 100644
--- a/docs/SymbolTable.md
+++ b/docs/SymbolTable.md
@@ -2,21 +2,21 @@
每个图形文件都包含有9个固定的符号表。不能往数据库里添加新的符号表。如图层表(LayerTable),其中包含图层表记录,还有块表(BlockTable),其中包含块表记录等。所有的图形实体(线、圆、弧等等)都属于一个块表记录。缺省情况下,任何图形文件都包含为模型空间和图纸空间预定义的块表记录。每个符号表都有对应的符号表记录,可以理解为符号表是一个集合,而符号表记录是这个集合的元素。CAD的符号表和符号表记录的对应关系如下:
-| 名称 | 符号表 | 符号表记录 |
-| :------------: | :------------: | :------------------: |
-| 块表 | BlockTable | BlockTableRecord |
-| 标注样式表 | DimStyleTable | DimStyleTableRecord |
-| 图层表 | LayerTable | LayerTableRecord |
-| 线型表 | LinetypeTable | LinetypeTableRecord |
-| 注册应用程序表 | RegAppTable | RegAppTableRecord |
-| 字体样式表 | TextStyleTable | TextStyleTableRecord |
-| 坐标系表 | UcsTable | UcsTableRecord |
-| 视口表 | ViewportTable | ViewportTableRecord |
-| 视图表 | ViewTable | ViewTableRecord |
+| 名称 | 符号表 | 符号表记录 |
+|:-------:|:--------------:|:--------------------:|
+| 块表 | BlockTable | BlockTableRecord |
+| 标注样式表 | DimStyleTable | DimStyleTableRecord |
+| 图层表 | LayerTable | LayerTableRecord |
+| 线型表 | LinetypeTable | LinetypeTableRecord |
+| 注册应用程序表 | RegAppTable | RegAppTableRecord |
+| 字体样式表 | TextStyleTable | TextStyleTableRecord |
+| 坐标系表 | UcsTable | UcsTableRecord |
+| 视口表 | ViewportTable | ViewportTableRecord |
+| 视图表 | ViewTable | ViewTableRecord |
那么如何来操作这些符号表呢?下面是一个新建图层的例子:
-```c#
+```csharp
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
@@ -43,7 +43,7 @@ using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
上面的例子用了20多行的代码来完成一个很简单的功能,这就是AutoCAD提供的api太过于基础,没有进行进一步的封装造成。那么如果我们单独为图层表封装一个函数来处理图层表,其他的8个符号表也要同样的各自封装函数,这样看起来没什么问题,但是对于代码的复用却没有很好的考虑进去。仔细思考一下,其实对于符号来说无非就是增删改三个主要的操作等,对于符号表记录来说无非就是一些属性的操作,增加实体的操作等。那么有没有一种办法可以统一管理9个符号表呢?其实AutoCAD提供了9个符号表和符号表记录的抽象基类,SymbolTable和SymbolTableRecord,但是这两个类提供的功能又很简单,只有寥寥几个函数和属性,完全不能满足我们的需求。因此ifoxcad内裤提供了符号表类来封装9个符号表的大部分功能。那么用内裤来完成上述的操作是什么样子的呢?见下面的例子:
-```c#
+```csharp
// 以下代码采用最新的c#版本语法
using var tr = new DBTrans(); // 打开事务
var layertable = tr.LayerTable.Add("MyLayer"); //添加图层
@@ -67,8 +67,6 @@ var layertable = tr.LayerTable.Add("MyLayer"); //添加图层
看,我教会了你操作图层表,那么其他的8个表你都会了,都是一样的操作。
-
-
## 块表添加图元
一般的情况下,添加图元的操作都是要在事务里完成。目前大部分的添加图元的自定义函数都是DataBase或Editor对象的扩展函数。但是实际上添加图元的本质是读写图形数据库,具体的手段是对块表里的块表记录的读写。而实际的操作其实都是在事务里完成,所以符合cad操作规则的写法其实应该是事务作为一系列操作的主体来进行。因此ifoxcad内裤的封装思路为:扩展块表记录的函数,在事务管理器类里通过属性调用AddEntity函数来添加图元。
@@ -82,8 +80,8 @@ var layertable = tr.LayerTable.Add("MyLayer"); //添加图层
下面看示例:
- 添加图元到当前空间
-
- ```c#
+
+ ```csharp
// 以下代码采用最新的c#版本语法
using var tr = new DBTrans(); //开启事务管理器
var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线
@@ -91,8 +89,8 @@ var layertable = tr.LayerTable.Add("MyLayer"); //添加图层
```
- 添加图元到模型/图纸空间
-
- ```c#
+
+ ```csharp
// 以下代码采用最新的c#版本语法
using var tr = new DBTrans(); //开启事务管理器
var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线
@@ -102,48 +100,47 @@ var layertable = tr.LayerTable.Add("MyLayer"); //添加图层
```
- 添加图元到块表
-
- ```c#
+
+ ```csharp
// 以下代码采用最新的c#版本语法
using var tr = new DBTrans(); //开启事务管理器
var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线
var btr = tr.BlockTable.Add("test"); //定义一个块表记录
btr.AddEntity(line1); // 将直线添加到当前控件的块表记录
```
-
+
那么大家猜一猜,这个添加到块表是实现了一种什么样的功能。
- 块表
-
+
块表这里需要特殊的说明一下:
-
+
比如说添加一个块,用如下代码:
-
+
`tr.BlockTable.Add(blockName, btr => btr.AddEntity(ents));`
-
+
这里的blockName就是块名,ents就是图元列表。这种方式虽然可以更细粒度的控制定义的块。
-
+
插入块参照,比如:
-
+
`tr.InsertBlock(point,objectid); // 用于插入块参照,提供了重载函数来满足不同的需求`
- 其他函数的介绍
-
+
`tr.BlockTable.GetRecord()` 函数,可以获取到块表的块表记录,同理层表等符号表也有同样的函数。
-
+
`tr.BlockTable.GetRecordFrom()` 函数,可以从文件拷贝块表记录,同理层表等符号表也有同样的函数。
-
+
`tr.BlockTable.GetBlockFrom()` 函数,从文件拷贝块定义,同理层表等符号表也有同样用途的函数。
- 添加图元函数
-
+
内裤提供了一些便利的添加图元函数,可以不用先定义一个entity对象,然后添加到块表记录。
-
- ```c#
+
+ ```csharp
using var tr = new DBTrans();
tr.CurrentSpace.AddLine(new Point3d(0,0,0),new Point3d(1,1,0));
tr.CurrentSpace.AddCircle(new Point3d(0,0,0),10);
```
-
diff --git a/docs/WPF.md b/docs/WPF.md
index 08d7c28c998bb6de4a1ef40db96a0110928ae9a0..73f4f1116be4ef9cff68117b0f2fd86acf32d382 100644
--- a/docs/WPF.md
+++ b/docs/WPF.md
@@ -225,7 +225,7 @@ public class TestViewModel : ViewModelBase
首先是在xaml里引入命名空间。
-`xmlns:eb="clr-namespace:IFoxCad.WPF;assembly=IFoxCad"`
+`xmlns:eb="clr-namespace:IFoxCAD.WPF;assembly=IFoxCAD.WPF"`
然后
diff --git a/docs/autoreg.md b/docs/autoreg.md
new file mode 100644
index 0000000000000000000000000000000000000000..72f377c24b7129336ebfa5a8e22f55fbc57697c5
--- /dev/null
+++ b/docs/autoreg.md
@@ -0,0 +1,62 @@
+## 自动加载与初始化
+
+### 1、简单版
+
+为了将程序集的初始化和通过写注册表的方式实现自动加载统一设置,减少每次重复的工作量,类裤提供了`AutoLoad`抽象类来完成此功能,只要在需要初始化的类继承`AutoLoad`类,然后实现`Initialize()` 和 `Terminate()` 两个函数就可以了。
+特别强调的是,一个程序集里只能有一个类继承,不管是不是同一个命名空间。
+
+如果要将dll的目录加入支持文件目录,请在 `Initialize` 函数中调用`AppendSupportPath(CurrentDirectory.FullName);`
+
+其他需要初始化执行的函数及设置都需要在 `Initialize` 函数中执行。
+
+### 2、功能版
+
+使用特性进行分段初始化是目前最佳选择,下面的说明已和最新版本不符,等待修正吧。
+
+```csharp
+ using Autodesk.AutoCAD.Runtime;
+ using IFoxCAD.Cad;
+ using System;
+ using System.Reflection;
+
+/*
+ * 自动执行接口
+ * 这里必须要实现一次这个接口,才能使用 IFoxInitialize 特性进行自动执行
+ */
+public class CmdINI : AutoRegAssem
+{
+ // 这里可以写任何普通的函数,也可以写下面 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 特性
+ }
+ [IFoxInitialize(isInitialize: false)] // 特性的参数为false的时候就表示卸载时执行的函数
+ public void Terminate()
+ {
+ // TODO 您想在关闭cad时自动执行的函数
+ }
+}
+```
diff --git "a/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" "b/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png"
new file mode 100644
index 0000000000000000000000000000000000000000..a9d08c483b80f21d4b0ac6a0afe80f9b6b4233e6
Binary files /dev/null and "b/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" differ
diff --git a/docs/png/nuget.png b/docs/png/nuget.png
new file mode 100644
index 0000000000000000000000000000000000000000..d0af980fedd9eca39d0e0bf787111685242994ac
Binary files /dev/null and b/docs/png/nuget.png differ
diff --git a/docs/png/nuget1.png b/docs/png/nuget1.png
new file mode 100644
index 0000000000000000000000000000000000000000..91983ffef3b246ea796296b14fe09963663de184
Binary files /dev/null and b/docs/png/nuget1.png differ
diff --git a/docs/png/standard.png b/docs/png/standard.png
new file mode 100644
index 0000000000000000000000000000000000000000..dfc34fecb32120f54436115208a4abaea2dac516
Binary files /dev/null and b/docs/png/standard.png differ
diff --git "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
index d8282200a6734c08bfbb1b74d08845f5806f51e9..f96d39d487c1f6c2af8a2f3257fa3cc3bbfd619d 100644
--- "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
+++ "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md"
@@ -1,4 +1,68 @@
-# 关于IFoxCAD的架构说明
+# IFoxCAD的架构说明
+
+AutoCAD 的 .net api 的架构是如下这样的:
+
+1. Application 对象
+
+```mermaid
+graph LR;
+a(Application)-->DocumentManager
+a-->DocumentWindowCollection
+a-->InfoCenter
+a-->MainWindow
+a-->MenuBar
+a-->MenuGroups
+a-->Preferences
+a-->Publisher
+a-->StatusBar
+a-->UserConfigurationManager
+```
+
+2. Document 对象
+
+```mermaid
+graph LR;
+Application-->DocumentManager-->b[Document]
+b-->Database
+b-->Editor
+b-->GraphicsManager
+b-->StatusBar
+b-->TransactionManager
+b-->UserData
+b-->Window
+```
+
+3. Database 对象
+
+```mermaid
+flowchart TB;
+subgraph NamedDictionaris
+ direction TB
+ Layout-Dictionary-->Object
+ Others-->OtherObject
+end
+subgraph Tables
+ direction TB
+ BlockTable-->BlockTableRecord-->Entity
+ OthersTable-->OthersTableRecord
+end
+Application-->DocumentManager-->Document-->d[Database]-->Tables
+d-->NamedDictionaris
+```
+
+4. Transation 对象
+
+```mermaid
+flowchart LR;
+subgraph Transation
+ direction LR
+ f(StartTransation)--modify objects-->e{isOK}
+ e--Yes-->h(commit)
+ e--No-->abort
+end
+h--write-->d[Database]
+g[Document or Database]--start-->f
+```
IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核,即DBTrans、SymbolTable、ResultData、SelectFilter等基础类,其他的功能都通过扩展方法的方式来实现。
@@ -7,33 +71,42 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核
## 一、组织结构图
- IFoxCAD
- - IFoxCAD.Cad - cad相关的类库
- - LinqEx - linq扩展类
- - LoopList - 环链表
- - IFoxCAD.Basal - cad以外常用的类库
- - Runtime - 包含系统级别的功能
- - AcadVersion - cad版本号类
- - AssemInfo - 程序集信息
- - AutoRegAssem - 程序集加载类型
- - DBTrans - 事务处理类
- - Env - 系统管理类
- - SymbolTable - 符号表类
- - ExtensionMethod - 扩展函数,以Ex结尾
- - SymbolTableEx - 符号表扩展类
- - SymbolTableRecordEx - 符号表记录扩展类
- - EntityEx - 实体扩展类
- - 。。。。。。
- - ResultData
- - 待补充。。。
- - SelectionFilter
- - 待补充。。。
- - IFoxCAD.WPF - wpf的mvvm模式相关的类库
- - 待补充。。。
-
- 
- 
- 
-## 二、关于DBTrans类的说明
+
+ - IFoxCAD.Basal - cad以外常用的类库
+
+ - LinqEx - linq扩展类
+
+ - LoopList - 环链表
+
+ - IFoxCAD.Cad - cad相关的类库
+
+ - Runtime - 包含系统级别的功能
+
+ - AcadVersion - cad版本号类
+ - AssemInfo - 程序集信息
+ - AutoRegAssem - 程序集加载类型
+ - DBTrans - 事务处理类
+ - Env - 系统管理类
+ - SymbolTable - 符号表类
+
+ - ExtensionMethod - 扩展函数,以Ex结尾
+
+ - SymbolTableEx - 符号表扩展类
+ - SymbolTableRecordEx - 符号表记录扩展类
+ - EntityEx - 实体扩展类
+ - 。。。。。。
+
+ - ResultData
+
+ - 待补充。。。
+
+ - SelectionFilter
+
+ - 待补充。。。
+
+ - IFoxCAD.WPF - wpf的mvvm模式相关的类库
+
+ ## 二、关于DBTrans类的说明
### 2.1 为什么要构建DBTrans类?
@@ -45,14 +118,16 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核
### 2.2 关于DBTrans类的具体构成元素的意义
-DBTrans类里基本的封装就是Transaction,然后是Document、Database、Editor、符号表、命名字典等,而抓这些其实都是cad二次开发关于图元操作经常打交道的概念。
+DBTrans类里基本的封装就是Transaction,然后是Document、Database、Editor、符号表、命名字典等,而这些其实都是cad二次开发关于图元操作经常打交道的概念。
DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的相关类库,通过这些属性就可以对数据进行相应的操作。特别是符号表中最常用的就是块表,通过对块表的操作来实现添加图元等。
### 2.3 DBTrans类应该具有的成员
+
为了尽量少的封装方法,减少类的复杂度,目前计划的方法主要为:
属性:
+
- Top ---返回当前事务
- Database ---数据库
- Document ---文档
@@ -60,11 +135,13 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的
- Trans ---事务管理器
构造函数:
+
- DBTrans(Document doc = null, bool commit = true)
- DBTrans(Database database, bool commit = true)
- DBTrans(string fileName, bool commit = true)
符号表:
+
- BlockTable 块表
- LayerTable 层表
- TextStyleTable 文字样式表
@@ -76,10 +153,12 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的
- ViewportTable 视口表
方法:
+
- GetObject ---根据对象id获取图元对象
- 。。。
接口:
+
- Abort ---放弃事务
- Commit ---提交事务
- Dispose --- 执行与释放非托管资源
@@ -96,10 +175,13 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的
- 有了这个类,DBTrans类就可以直接通过属性获取符号表的关联关系,然后进行符号表的处理。
### 3.2 SymbolTable类应该具有的成员
+
属性:
+
- CurrentSymbolTable ---当前的符号表对象
方法:
+
- this ---索引器符号表记录函数
- Add ---添加符号表记录函数
- Remove --- 删除符号表记录函数(层表请使用扩展方法Delete)
@@ -109,15 +191,6 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的
- Has --- 判断符号表是否有符号表记录的函数
- 。。。
-特殊说明:当符号表为块表时,上述函数实际操作的是块定义、属性定义等。所以为了添加图元,需要特殊写法。
+特殊说明:当符号表为块表时,上述函数实际操作的是块定义、属性定义等。所以为了添加图元,需要特殊写法,原因在于cad的实体都是存在符号表记录里的,通常为模型这个块表记录。
# 慢慢完善,想到哪写到哪。。。
-
-
-
-
-
-
-
-
-
diff --git a/src/Basal/Directory.Build.props b/src/Basal/Directory.Build.props
new file mode 100644
index 0000000000000000000000000000000000000000..77a2d3711db05b158825e750d59ed1f4f864e9a9
--- /dev/null
+++ b/src/Basal/Directory.Build.props
@@ -0,0 +1,37 @@
+
+
+
+ 0.5.2.4
+ 完善源码包,源码包映射原始目录
+
+
+
+ preview
+ enable
+ true
+ ..\..\..\bin\$(Configuration)\
+ true
+ true
+ True
+ True
+
+
+
+
+
+ InspireFunction
+ xsfhlzh;vicwjb;liuqihong
+ InspireFunction
+ 基于.NET的二次开发基本类库.
+ MIT
+ true
+ https://gitee.com/inspirefunction/ifoxcad
+ https://gitee.com/inspirefunction/ifoxcad.git
+ git
+ IFox;C#;NET;Common;Basal
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Basal/IFox.Basal.Shared/CLS/Index.cs b/src/Basal/IFox.Basal.Shared/CLS/Index.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b84f4dffd68334952188669e6fa487d76dcb89d0
--- /dev/null
+++ b/src/Basal/IFox.Basal.Shared/CLS/Index.cs
@@ -0,0 +1,151 @@
+// 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.
+#if !NOINDEX
+namespace System;
+
+
+#if NET45
+using System.Runtime.CompilerServices;
+#endif
+/// 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();
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Basal/IFox.Basal.Shared/CLS/Range.cs b/src/Basal/IFox.Basal.Shared/CLS/Range.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0318216b8a9dc01a2712633037053f66bdf83c07
--- /dev/null
+++ b/src/Basal/IFox.Basal.Shared/CLS/Range.cs
@@ -0,0 +1,107 @@
+// 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.
+#if !NORANGE
+namespace System;
+
+
+
+#if NET45
+using System.Runtime.CompilerServices;
+#endif
+
+/// 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);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs b/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..841c0d59100a271c323809fdee0fedd34f618f1e
--- /dev/null
+++ b/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs
@@ -0,0 +1,57 @@
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using IFoxCAD.Basal;
+
+namespace System.Runtime.CompilerServices;
+
+/*
+ * 1.编译提示多个程序集中定义,屏蔽不了,但是不影响编译
+ * 2.发现可以通过定义一个条件编译常量来进行屏蔽。
+ * 3.普通包会提示编译器缺少GetSubArray函数,但是源码包不会。所以解决方案就是使用普通包的时候安装TA.System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray nuget包来解决,此包为一个符号包,不会生成多余的dll
+ */
+
+
+#if !NORuntimeHelpers
+///
+///
+///
+internal static class RuntimeHelpers
+
+{
+ ///
+ /// Slices the specified array using the specified range.
+ ///
+ public static T[] GetSubArray(T[] array, Range range)
+ {
+ //if (array == null)
+ // throw new ArgumentNullException(nameof(array));
+ array.NotNull(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
diff --git a/src/Basal/IFox.Basal.Shared/CLS/TupleElementNamesAttribute.cs b/src/Basal/IFox.Basal.Shared/CLS/TupleElementNamesAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..93e61930c31b8277948fa060629cb1d813a04ba1
--- /dev/null
+++ b/src/Basal/IFox.Basal.Shared/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/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs b/src/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c20902433c6b2e27faccc0f8cf436837c42e460b
--- /dev/null
+++ b/src/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs
@@ -0,0 +1,2152 @@
+// 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
+#if !NOVALUETUPLE
+
+using System.Diagnostics;
+using System.Numerics.Hashing;
+/*
+ * 惊惊:
+ * 首先是因为有人想要编译的时候只形成一个dll,然后把元组塞入IFox,同时也补充了NET35没有元组的遗憾.
+ *
+ * 而利用nuget元组包必然会形成依赖地狱.
+ *
+ * 如果你的工程使用了nuget元组包,就造成了必须要剔除IFox.
+ *
+ * 改IFox的元组命名空间倒是可以分离两者,但是 vs编译器 无法识别带其他命名空间的元组.
+ * 所以元组本身就是冲突的,需要把其他元组卸载掉,由IFox提供.
+ */
+
+/*
+ * 1. 元组是net47之后提供的特性,所以net47之前的版本是都没有的
+ * 2. 通过定义常量的办法将元组屏蔽,很奇怪的是源码包可以,但是普通包不行,所以推荐使用源码包 index和range的情况类似
+ * 这种问题就没有很好的解决方式,因为用了ifox就不能用其他的index,range,valuetuple类库,但是其他的三方库却依赖
+ * 这些类库,所以还是使用源码包吧。
+*/
+
+#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